#!/bin/bash

# этот файл во многом пример как не надо делать с точки зрения pl7
# skip crab_syntax

set -f

[[ "$@" != *'--server'* ]] && exec 0</dev/null

trap 'aa' USR1
aa(){
	sleep 3600
}
opt_help(){
	echo 'example1:
	myprog -i qwe -r asd --input=12345 SRC DST DST2 DST3 DST4
	i=$( opt_get -i "$@" )
	r=$( opt_get -r "$@" )
	input=$( opt_get --input "$@" )
	SRC=$( opt_get 1 "$@" )
	DST=$( opt_get 2 "$@" )

	example2:
	while read arg; do
		echo $arg
	done <<<$( opt_get 0 "$@" )

	example3:
	OPTS[0]="-i --input FILENAME name file"
	OPTS[1]="-r --rest R rest_comment"
	opt_pars "$@"
	echo $FILENAME $R

	example4:
	opt_usage "$0 [options] SRC DST"
	Usage: $0 [options] SRC DST
	-i, --input		name file
	-r, --rest		rest_comment

	'
}

opt_get(){
	local arg_name=$1
	local argc=0
	local ret=1
	# hack
	[ "$arg_name" = "-r" ] && return 0
	[ "$arg_name" = "--recursive" ] && return 0

	while shift && [ "$#" -gt "0" ]; do
		[ "$1" = "-r" ] && continue
		[ "$1" = "--recursive" ] && continue

		if [[ "$arg_name" == [0-9]* ]]; then
			[[ "$1" == "--"* ]] && { continue; }
			[[ "$1" == "-"* ]] && { shift; continue; }
			[ "$arg_name" = "0" ] && { echo "${1}"; ret=0; continue; }
			let argc=argc+1
			[ ${argc} -lt ${arg_name}  ] && { continue; }
			echo "$1"
			return 0
		fi	
		if [[ "$arg_name" == [-][^-]* ]] && [ "$1" = "$arg_name" ]; then
			shift;
			echo "$1"
			return 0
		fi
		if [[ "$arg_name" == "--"* ]] && [[ "$1" == "$arg_name"=* ]]; then
			echo "${1#*=}"
			return 0
		fi
	done
	return $ret
}
opt_pars(){
	local _i=0 _var= _val= _short= _long= _comment=
	for((_i=0;_i<${#OPTS[@]}; _i++)); do
		read _short _long _var _comment <<< ${OPTS[$_i]}
		_val="$( opt_get $_short "$@" )" || _val="$( opt_get $_long "$@" )" || _val=""
		eval $_var='"$_val"' || true
	done
}
opt_usage(){
	local i=0 var= short= long= comment=
	echo "Usage: $@"
	for((i=0;i<${#OPTS[@]}; i++)); do
		read short long var comment <<< ${OPTS[$i]}
		echo -e "\t$short, $long\t\t$comment"
	done
}


# это и клиент и сервер, патамушто ))
# --server
#############################################################################################
#	23.08.2012 osv Новый алгоритм
#	тк файлы очень большие, нет возможности кешировать их блоки во временной директории
#	поэтому сверяем c серверным bmap и сразу отправляем на сервер измененные блоки
#	Алгоритм, у нас есть серверный map файла, в нем хранятся hash каждого блока файла
#	мы высчитываем локальных hash и если он не совпадает, то отправляем файл и меняем map
#	в отличии от rsync мы не делаем read серверного файла, и не нагружаем сервер
#############################################################################################

if [ -z "$1" ]; then
	opt_usage "$0 src dst"
	exit 255
fi
OPTS[0]="-k --key encrypt_pass key for encrypt"
OPTS[1]="-s --seek_file SEEK_FILE file content block number(для многопроходного живого синка ics_main.gdb)"
OPTS[2]="-n --no-history NO_HISTORY not create history blocks"
OPTS[3]="-f --fake-copy FAKE_COPY not really sync file, only create diff hash"
OPTS[4]="-O --ssh-options SSH_OPT use additional options for ssh. separate comma wo space -oStrictHostKeyChecking=no,-p22,-i/tmp/key.key"
OPTS[5]="-B --block-size BSIZE use additional options for ssh default 1024*1024"
OPTS[6]="-D --datesec DATESEC дата создания архива, важно для многофайловых архивов, это будет имя подкаталога"
OPTS[7]="-R --no-gzip NO_GZIP --no-gzip=1 or -R 1 не сжимать дельта файлы"
OPTS[8]="-P --ssh-persist SSH_PERSIST_SEC -P SEC использовать ControlMaster ControlPersist=SEC"
OPTS[9]="-r --recursive RECURSIVE --recursive=1 -r 1 copy directories recursively"
OPTS[10]="-E --exclude EXCLUDE example '*.lock *.tmp'"
OPTS[11]="-I --include INCLUDE copy only file mask example '*.lock *.tmp'"
OPTS[12]="-nd --no-direct-read NO_DIRECT_READ Do not use O_DIRECT on read"

lzop --help &>/dev/null || yum install -y lzop || apt-get install -y lzop || exit 1

BK_LIST_FILE=
IS_RECURSIVE=FALSE
# ввиду того что код сильно не crab_syntax и править его сейчас нет смысла вставим рекусию хаком самовызова
if [[ "$@" == *'-r '* ]]; then
	IS_RECURSIVE=TRUE
	datesec_exists=FALSE
	opt_pars "${@}"
	SRC="$( opt_get 1 "$@" )"
	DST="$( opt_get 2 "$@" )"
	for opt in "${@}"; do
		[[ "$opt" == *'--exclude'* ]] && continue
		[[ "$opt" == *'--include'* ]] && continue
		[ "$opt" = "$SRC" ] && continue
		[ "$opt" = "$DST" ] && continue
		[ "$opt" != '-r' ] && opts=( "${opts[@]}" "$opt" )
		[ "$opt" = '-D' ] && datesec_exists=TRUE
	done
	if [ "$datesec_exists" = FALSE ]; then
		RECUR_DATESEC="$(date +%s)"
		opts=( "-D" "$RECUR_DATESEC" "${opts[@]}" )
	else
		RECUR_DATESEC="$DATESEC"
	fi
	#for opt in "${opts[@]}"; do
	#	echo $opt
	#done
	SRC="${SRC%/}"
	DST="${DST%/}"
	BK_LIST_FILE=''
	EXCLUDE="${EXCLUDE},*/.BMAP/*,*/.INFO/*,*/.BLOG/*,*/.BACKUP/*,*.crab_sync,*.hashbin"
	find $SRC -type f > /tmp/crab_sync_find.$$
	while read -r srcfile; do
		srcdir="${srcfile%/*}"
		srcdir="${srcdir/$SRC/}"
		srcdir="${srcdir#/}"
		dstdir="${DST}/${srcdir}/"
		dstdir="${dstdir/\/\//}"
		for exc in ${EXCLUDE//,/ }; do
			[[ "$srcfile" == ${exc} ]] \
				&& { echo "$srcfile - SKIP"; continue 2; }
		done
		if [ -n "${INCLUDE}" ]; then
			for inc in  ${INCLUDE//,/ }; do
				[[ "$srcfile" != ${inc} ]] \
					&& { echo "$srcfile - SKIP"; continue 2; }
			done
		fi
		"$0" "${opts[@]}" "$srcfile" "$dstdir" || __exit $?
		BK_LIST_FILE="${BK_LIST_FILE}$srcfile"$'\n'
	done < /tmp/crab_sync_find.$$
	rm -f /tmp/crab_sync_find.$$
fi
########### Сначала сервер
###########
fwrite(){
	# если это уже второй и более бекап то делаем резервные копии изменных файлов туду день неделя месяц год
	# для этого смотрим что собираемся писать в существующий блок
	# nikolay 2021.03 добавил проверку что файл уже существует, т.к. его уже может сохранить fresize при подрезке
	# возможно, это привело бы к проблемам, когда повторно используется -D <время>, как в vm backup,
	# но исключая перезапись блоков мы наоборот сохраняем изначальное содержимое файла до бекапов - т.е. возможно исправляем еще один баг
	# TODO2: мб стоит и в других местах отрубить перезапись блоков
	if [ $((i*BSIZE)) -lt $DST_FSIZE  ]; then
		if [ -n "$NO_HISTORY" ]; then
			[ ! -f "$HISTORY_DIR/$i.part" ] && \
				echo $BHASH > "$HISTORY_DIR/$i.part"
		else
			if [ "$NO_GZIP" != 1 ]; then
				[ ! -f "$HISTORY_DIR/$i.part.gz" ] && \
					dd conv=noerror iflag=direct if=$DST_FILE skip=$i bs=$BSIZE count=1 2>/dev/null | gzip -1 -c | dd conv=noerror bs=4M oflag=direct of="$HISTORY_DIR/$i.part.gz" 2>/dev/null
				#dd conv=noerror iflag=direct oflag=direct if=$DST_FILE skip=$i bs=$BSIZE count=1 of="$HISTORY_DIR/$i.part.gz" 2>/dev/null
			else
				[ ! -f "$HISTORY_DIR/$i.part" ] && \
					dd conv=noerror iflag=direct oflag=direct if=$DST_FILE skip=$i bs=$BSIZE count=1 of="$HISTORY_DIR/$i.part" 2>/dev/null
			fi
		fi
	fi
	[ -n "$FAKE_COPY" ] && return 0
	dd conv=noerror oflag=direct of=$DST_FILE seek=$i bs=$BSIZE count=1 conv=notrunc iflag=fullblock &>/dev/null #oflag=direct &>/dev/null
	#    	dd conv=noerror seek=$i bs=$BSIZE count=1 conv=notrunc &>/dev/null

	echo $BHASH | dd conv=noerror of=$DST_BMAP seek=$((i*(HASH_SIZE+1))) bs=1 count=$((HASH_SIZE+1)) conv=notrunc &>/dev/null
}
fresize(){
	DST_FSIZE=`stat -c %s $DST_FILE`
	DST_BMAP_SIZE=`stat -c %s $DST_BMAP`
	SRC_BMAP_SIZE=$((((SRC_FSIZE-1)/BSIZE+1)*(HASH_SIZE+1)))
	[ -n "$FAKE_COPY" ] && return 0
	local hash t ii
	#return 0
	if [ "$DST_BMAP_SIZE" -gt "$SRC_BMAP_SIZE" ]; then
		dd conv=noerror if=$DST_BMAP skip=$((SRC_BMAP_SIZE)) bs=1 2>/dev/null >$DST_BMAP.tail
		ii=$(((SRC_BMAP_SIZE)/(HASH_SIZE+1)))
		while read hash t; do
			[ "${#hash}" -lt "$HASH_SIZE" ] && break
			if [ -n "$NO_HISTORY" ]; then
				echo $BHASH > "$HISTORY_DIR/$ii.part"
			else
				if [ "$NO_GZIP" != 1 ]; then
					dd conv=noerror iflag=direct if=$DST_FILE skip=$ii bs=$BSIZE count=1 2>/dev/null | gzip -1 -c > "$HISTORY_DIR/$ii.part.gz" 2>/dev/null
				else
					dd conv=noerror iflag=direct oflag=direct if=$DST_FILE of=$HISTORY_DIR/$ii.part skip=$ii bs=$BSIZE count=1 &>/dev/null
				fi
			fi
			let ii=ii+1
		done < $DST_BMAP.tail
		rm -f  $DST_BMAP.tail
		dd conv=noerror of=$DST_BMAP seek=$SRC_BMAP_SIZE bs=1 count=0 &>/dev/null
	fi
	if [ "$DST_FSIZE" -gt "$SRC_FSIZE" ]; then
		# Подрезка файла
		#
		# Т.к. подрезка может быть в пределах ордного блока
		# сохраним подрезаемый блок в хистори. Другие блоки сохранятся
		# из кода выше
		#
		# Если попадаем ровно в BSIZE, то в бекап кладем следующий блок
		local ii="$((SRC_FSIZE/BSIZE))"
		if [ -n "$NO_HISTORY" ]; then
			echo $BHASH > "$HISTORY_DIR/$ii.part"
		else
			if [ "$NO_GZIP" != 1 ]; then
				dd conv=noerror iflag=direct if=$DST_FILE skip=$ii bs=$BSIZE count=1 2>/dev/null \
					| gzip -1 -c \
					| dd conv=noerror bs=4M oflag=direct of="$HISTORY_DIR/$ii.part.gz" 2>/dev/null
			else
				dd conv=noerror iflag=direct oflag=direct if=$DST_FILE of=$HISTORY_DIR/$ii.part skip=$ii bs=$BSIZE count=1 &>/dev/null
			fi
		fi
		dd conv=noerror of=$DST_FILE seek=$SRC_FSIZE bs=1 count=0 &>/dev/null
	fi
}
fstat_update(){
	mkdir -p $BMAP_DIR;
	[ ! -f $DST_FILE ] && touch $DST_FILE;
	DST_FILE_MODIFY="$BMAP_DIR/${SHORT_FILE}.dst_modify"
	stat -c %Y $DST_FILE > $DST_FILE_MODIFY;
	touch $DST_BMAP
}

fstat_update2(){
	local DST_FILE="$1"
	local DST_DIR=${DST_FILE%/*}
	local SHORT_FILE=${DST_FILE##*/}
	local BMAP_DIR="$DST_DIR/.BMAP"
	local DST_BMAP="$BMAP_DIR/$SHORT_FILE.bmap"
	DST_FILE_MODIFY="$BMAP_DIR/${SHORT_FILE}.dst_modify"
	$SSH "mkdir -p $BMAP_DIR;
	[ ! -f $DST_FILE ] && touch $DST_FILE;
	stat -c %Y $DST_FILE > $DST_FILE_MODIFY;
	touch $DST_BMAP"
}

do_server(){
	once_init=0
	if [[ "${DST}" = *:* ]]; then
		decomp='lzop -d -c '
	else
		decomp='cat '
	fi
	$decomp \
		| while read -r cmd DST_FILE TMP_BLOCK i BHASH SRC_FSIZE SRC_MODIFY ENC_BSIZE tmp; do
			#echo "Server recv $cmd $DST_FILE $TMP_BLOCK $i $BHASH $SRC_FSIZE $SRC_MODIFY $ENC_BSIZE $tmp"
			BSIZE=$ENC_BSIZE
			DST_DIR=${DST_FILE%/*}
			SHORT_FILE=${DST_FILE##*/}

			BMAP_DIR="$DST_DIR/.BMAP"
			DST_BMAP="$BMAP_DIR/$SHORT_FILE.bmap"
			BLOG_DIR="$DST_DIR/.BLOG"
			HISTORY_DIR="$BLOG_DIR/$SRC_MODIFY/$SHORT_FILE"

			if [ -n "$FAKE_COPY" ]; then
				HISTORY_DIR="${HISTORY_DIR}_fake/"
			fi
			if [ "$once_init" = "0" ]; then
				mkdir -p "$BMAP_DIR"
				mkdir -p "$BLOG_DIR"
				mkdir -p "$HISTORY_DIR"
				[ ! -f $DST_FILE ] && touch $DST_FILE
				[ ! -f $DST_BMAP ] && touch $DST_BMAP
				stat -c %s $DST_FILE > $HISTORY_DIR/FILESIZE
				once_init=1
			fi

			case $cmd in
			fwrite)
				fresize
				fwrite
				fstat_update
				;;
			#нельзя тк dd читает блоками BSIZE и надо это переделать потом может быть
			#		ftrunc)
			#			fresize
			#			;;
			#		fclose)
			#			fclose
			#			;;
			*)
				continue
				;;
			esac
		done
	__exit 0
}

#######################################################################################
# запустили в режиме создания bmap
#######################################################################################


recreate_dst_bmap(){
	mkdir -p "$DST_DIR/.BMAP/"
	$DST_DIR/.hashbin $DST_FILE $BSIZE > $DST_FILE_BMAP
	__exit 0
}


########################################################################################
# теперь клиент главный код
########################################################################################

sync_file() {
	local srv_bcount=-1
	declare -a srv_bhash
	declare -a seek_a
	local hash= tmp= i= hash= si= seek= count=
	[ ! -s $CACHE_BMAP ] && touch $CACHE_BMAP
	if [ "$encrypt_pass" != "" ]; then
		ENC_SRC_FSIZE=$((SRC_FSIZE / (BSIZE)*(BSIZE+16)+(((SRC_FSIZE % BSIZE)/16+1)*16) ))
		ENC_BSIZE=$((BSIZE+16))
	else
		ENC_SRC_FSIZE=$SRC_FSIZE
		ENC_BSIZE=$BSIZE
	fi

	while read hash tmp; do
		[ -z "$hash" ] && break
		((srv_bcount++)) || true
		srv_bhash[$srv_bcount]=$hash
	done < $CACHE_BMAP
	i=-1;
	if [ -n "$SEEK_FILE" ]; then
		si=-1
		while read seek; do
			[ -z "$seek" ] && break
			((si++)) || true
			#echo $si $seek >&2
			seek_a[$si]=$seek
		done < $SEEK_FILE
	fi
	count=0
	echo 0 > /tmp/fsend.$$
	touch /tmp/error_dd.$$
	$HASHBIN $SRC $BSIZE $SEEK_FILE \
		| (
			set -e;
			while read fhash musor; do
				# '-' - flush pipe
				[ "$fhash" == '-' ] && continue
				if [ -z "$SEEK_FILE" ]; then
					((i++)) || true
				else
					i=${seek_a[$count]}
				fi
				[ $i -le $srv_bcount ] && srv_hash=${srv_bhash[$i]} || srv_hash="-"
				echo -n "$count ${SRC_FSIZE}($(($SRC_FSIZE/$BSIZE))) $((i*BSIZE))($i) " >&2
				((count++)) || true
				[ $i -le $srv_bcount ] && [ "$fhash" = "$srv_hash" ] && { echo "[$i<$srv_bcount & $fhash=${srv_hash}] - skip" >&2; continue; }
				# посылаем команду fwrite
				echo fwrite "$DST_FILE" -1 $i $fhash $ENC_SRC_FSIZE $SRC_MODIFY $ENC_BSIZE "end"
				[ -n "$FAKE_COPY" ] && continue
				local iflag_param='iflag=direct'
				if [ -n "$NO_DIRECT_READ" ]; then
					iflag_param=''
				fi
				if [ "$encrypt_pass" != "" ]; then
					dd conv=noerror $iflag_param if=$SRC skip=$i bs=$BSIZE count=1 2>/tmp/dd.log.$$ | openssl enc -aes-128-cbc -k $encrypt_pass -nosalt
				else
					LANG=C timeout -s KILL 60 dd conv=noerror $iflag_param if=$SRC skip=$i bs=$BSIZE count=1 2>/tmp/dd.log.$$
				fi
				read -r FSEND < /tmp/fsend.$$
				echo "$((FSEND+BSIZE))" > /tmp/fsend.$$
				grep -v 'records' /tmp/dd.log.$$ >&2 || true
				# bmap update
				# echo $fhash | dd conv=noerror of=$CACHE_BMAP seek=$((i*(HASH_SIZE+1))) bs=1 count=$((1*($HASH_SIZE+1))) conv=notrunc &>/dev/null
			done
			#if [ $srv_bcount -gt $i ]; then
			#	# посылаем команду ftrunc
			#НЕЛЬЗЯ тк чтение идет 4мб echo ftrunc "$DST_DIR/${SRC##*/}" -1 -1 -1 $ENC_SRC_FSIZE $SRC_MODIFY $ENC_BSIZE "end"
			#fi
			#НЕЛЬЗЯ тк чтение идет 4мб echo fclose "$DST_DIR/${SRC##*/}" -1 -1 -1 $ENC_SRC_FSIZE $SRC_MODIFY $ENC_BSIZE "end"
			rm -f /tmp/error_dd.$$ /tmp/dd.log.$$
			exit 0
		)
	[ -f /tmp/error_dd.$$ ] && __exit 12
	# bmap trunc
	dd conv=noerror of=$CACHE_BMAP seek=$CACHE_BMAP_SIZE bs=1 count=0 &>/dev/null
	$SSH "  mkdir -p $DST_DIR/.BMAP/;"
	stat -c %Y $SRC | $SSH "dd conv=noerror of=$DST_FILE_SRC_MODIFY"
}
adlermap_create(){
	rm -f $CACHEDIR/adlermap
	echo "f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAcApAAAAAAABAAAAAAAAAADgWAAAAAAAAAAAAAEAAOAAI
AEAAHAAbAAYAAAAFAAAAQAAAAAAAAABAAEAAAAAAAEAAQAAAAAAAwAEAAAAAAADAAQAAAAAAAAgA
AAAAAAAAAwAAAAQAAAAAAgAAAAAAAAACQAAAAAAAAAJAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA
AAAAAAABAAAABQAAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAAAFwSAAAAAAAAXBIAAAAAAAAAACAA
AAAAAAEAAAAGAAAAYBIAAAAAAABgEmAAAAAAAGASYAAAAAAAjAIAAAAAAADAAgAAAAAAAAAAIAAA
AAAAAgAAAAYAAACIEgAAAAAAAIgSYAAAAAAAiBJgAAAAAACgAQAAAAAAAKABAAAAAAAACAAAAAAA
AAAEAAAABAAAABwCAAAAAAAAHAJAAAAAAAAcAkAAAAAAAEQAAAAAAAAARAAAAAAAAAAEAAAAAAAA
AFDldGQEAAAAjBEAAAAAAACMEUAAAAAAAIwRQAAAAAAALAAAAAAAAAAsAAAAAAAAAAQAAAAAAAAA
UeV0ZAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAv
bGliNjQvbGQtbGludXgteDg2LTY0LnNvLjIABAAAABAAAAABAAAAR05VAAAAAAACAAAABgAAABIA
AAAEAAAAFAAAAAMAAABHTlUAQubkIld0uyfPTvgOEen15ROQZg4DAAAAFwAAAAEAAAAGAAAAiMEg
AQAFUAsXAAAAGgAAAB0AAAC645J8QkXV7CkdjBzYcVgcOPKLHLmN8Q7r0+8OAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAqwAAABIAAAAAAAAAAAAAAAAAAAAAAAAAggAAABIAAAAAAAAAAAAAAAAAAAAA
AAAACwAAACAAAAAAAAAAAAAAAAAAAAAAAAAAGgAAACAAAAAAAAAAAAAAAAAAAAAAAAAAsgAAABIA
AAAAAAAAAAAAAAAAAAAAAAAAaQAAABIAAAAAAAAAAAAAAAAAAAAAAAAAiAAAABIAAAAAAAAAAAAA
AAAAAAAAAAAA0QAAABIAAAAAAAAAAAAAAAAAAAAAAAAAbgAAABIAAAAAAAAAAAAAAAAAAAAAAAAA
yAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAwQAAABIAAAAAAAAAAAAAAAAAAAAAAAAAnQAAABIAAAAA
AAAAAAAAAAAAAAAAAAAAWAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAUwAAABIAAAAAAAAAAAAAAAAA
AAAAAAAAgQAAABIAAAAAAAAAAAAAAAAAAAAAAAAAogAAABIAAAAAAAAAAAAAAAAAAAAAAAAAlgAA
ABIAAAAAAAAAAAAAAAAAAAAAAAAALgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAwAAAABIAAAAAAAAA
AAAAAAAAAAAAAAAAqgAAABIAAAAAAAAAAAAAAAAAAAAAAAAAugAAABIAAAAAAAAAAAAAAAAAAAAA
AAAATAAAABIAAAAAAAAAAAAAAAAAAAAAAAAA9gAAABAA8f8gFWAAAAAAAAAAAAAAAAAA4wAAABAA
8f/sFGAAAAAAAAAAAAAAAAAAegAAABEAGQAAFWAAAAAAAAgAAAAAAAAA6gAAABAA8f/sFGAAAAAA
AAAAAAAAAAAAjwAAABEAGQDwFGAAAAAAAAgAAAAAAAAAPAAAABIACwAACUAAAAAAAAAAAAAAAAAA
NgAAABIADgD4EEAAAAAAAAAAAAAAAAAAAGxpYnouc28uMQBfX2dtb25fc3RhcnRfXwBfSnZfUmVn
aXN0ZXJDbGFzc2VzAGFkbGVyMzIAX2ZpbmkAX2luaXQAbGliYy5zby42AGZmbHVzaABmZW9mAF9f
ZXJybm9fbG9jYXRpb24AcmVhZABnZXRwYWdlc2l6ZQBzdGRvdXQAZmNsb3NlAG1hbGxvYwBzdGRl
cnIAZnNjYW5mAGF0b2kAbHNlZWs2NABmcHJpbnRmAHNldHZidWYAZmNudGwAZm9wZW42NABzdHJl
cnJvcgBfX2xpYmNfc3RhcnRfbWFpbgBfZWRhdGEAX19ic3Nfc3RhcnQAX2VuZABHTElCQ18yLjIu
NQAAAAACAAIAAAAAAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAAACAAIAAgACAAEAAQACAAEA
AgABAAEAAAAAAAEAAQBCAAAAEAAAAAAAAAB1GmkJAAACAPsAAAAAAAAAKBRgAAAAAAAGAAAAAwAA
AAAAAAAAAAAA8BRgAAAAAAAFAAAAGwAAAAAAAAAAAAAAABVgAAAAAAAFAAAAGQAAAAAAAAAAAAAA
SBRgAAAAAAAHAAAAAQAAAAAAAAAAAAAAUBRgAAAAAAAHAAAAAgAAAAAAAAAAAAAAWBRgAAAAAAAH
AAAABQAAAAAAAAAAAAAAYBRgAAAAAAAHAAAABgAAAAAAAAAAAAAAaBRgAAAAAAAHAAAABwAAAAAA
AAAAAAAAcBRgAAAAAAAHAAAACAAAAAAAAAAAAAAAeBRgAAAAAAAHAAAACQAAAAAAAAAAAAAAgBRg
AAAAAAAHAAAACgAAAAAAAAAAAAAAiBRgAAAAAAAHAAAACwAAAAAAAAAAAAAAkBRgAAAAAAAHAAAA
DAAAAAAAAAAAAAAAmBRgAAAAAAAHAAAADQAAAAAAAAAAAAAAoBRgAAAAAAAHAAAADgAAAAAAAAAA
AAAAqBRgAAAAAAAHAAAADwAAAAAAAAAAAAAAsBRgAAAAAAAHAAAAEAAAAAAAAAAAAAAAuBRgAAAA
AAAHAAAAEQAAAAAAAAAAAAAAwBRgAAAAAAAHAAAAEgAAAAAAAAAAAAAAyBRgAAAAAAAHAAAAEwAA
AAAAAAAAAAAA0BRgAAAAAAAHAAAAFAAAAAAAAAAAAAAA2BRgAAAAAAAHAAAAFQAAAAAAAAAAAAAA
4BRgAAAAAAAHAAAAFgAAAAAAAAAAAAAASIPsCOiTAQAA6CICAADorQcAAEiDxAjD/zUaCyAA/yUc
CyAADx9AAP8lGgsgAGgAAAAA6eD/////JRILIABoAQAAAOnQ/////yUKCyAAaAIAAADpwP////8l
AgsgAGgDAAAA6bD/////JfoKIABoBAAAAOmg/////yXyCiAAaAUAAADpkP////8l6gogAGgGAAAA
6YD/////JeIKIABoBwAAAOlw/////yXaCiAAaAgAAADpYP////8l0gogAGgJAAAA6VD/////JcoK
IABoCgAAAOlA/////yXCCiAAaAsAAADpMP////8lugogAGgMAAAA6SD/////JbIKIABoDQAAAOkQ
/////yWqCiAAaA4AAADpAP////8logogAGgPAAAA6fD+////JZoKIABoEAAAAOng/v///yWSCiAA
aBEAAADp0P7///8ligogAGgSAAAA6cD+////JYIKIABoEwAAAOmw/v//AAAAAAAAAAAx7UmJ0V5I
ieJIg+TwUFRJx8AgEEAASMfBMBBAAEjHx5ELQADo3/7///SQkEiD7AhIiwWBCSAASIXAdAL/0EiD
xAjDkJCQkJCQkJCQkJCQkFVIieVTSIPsCIA9OAogAAB1S7t4EmAASIsFMgogAEiB63ASYABIwfsD
SIPrAUg52HMkZg8fRAAASIPAAUiJBQ0KIAD/FMVwEmAASIsF/wkgAEg52HLixgXrCSAAAUiDxAhb
ycNmZmYuDx+EAAAAAABIgz1IByAAAFVIieV0ErgAAAAASIXAdAi/gBJgAMn/4MnDkJBVSInlSIl9
6EiJdeBIi0XoSIlF8EiLReBIg+gBSANF8EiJRfhIi0X4ugAAAABI93XgSInQSPfYSANF+MnDVUiJ
5VNIgeyIEAAAib187///SIm1cO///8dFiAAAAADHRYwAAAAASMdFmAAAAABIx0WwAAAAAEjHRbgA
AAAASMdFwAAAAADHRYT/////SMdFyAAAAABIx0Xg/////+iU/f//SJhIiQUbCSAASIsFFAkgAEiD
wAJIAcBIBf///wFIicfoT/3//0iJRdhIi0XYSIlF0EiDRdACSIsV5wggAEiLRdBIidZIicfoFP//
/0iJRdDHRZAAAAAA6xGLRZBImMaEBYDv//8tg0WQAYF9kP8PAAB+5saFf////wDGhYHv//8gg718
7///An8Ux0WMFgAAAEjHRcgYEUAA6UUDAACDvXzv//8CD46rAAAASIOFcO///whIi4Vw7///SIsA
vgAAAABIice4AAAAAOjl/P//iUWUg32UAHkwSIuFcO///0iLELk+EUAASIsFDgggAEiJzkiJx7gA
AAAA6Eb9//+4AQAAAOkRAwAAi0WUvgMAAACJx7gAAAAA6Dj9//+JReiLReiAzECJReyLVeyLRZS+
BAAAAInHuAAAAADoFf3//4tFlL4DAAAAice4AAAAAOgB/f//iUXog7187///An4vSIOFcO///whI
i4Vw7///SIsASInH6Ev8//9ImEiJRbBIg32wAH8ISMdFsAAAEACDvXzv//8DfmRIg4Vw7///CLpN
EUAASIuFcO///0iLAEiJ1kiJx+h7/P//SIlFmEiDfZgAdTBIi4Vw7///SIsQuVARQABIiwUiByAA
SInOSInHuAAAAADoWvz//7gBAAAA6SUCAADHRYQBAAAASIsFCgcgALkAAAAAugIAAAC+AAAAAEiJ
x+g7+///6wGQSIN9mAB0PLlgEUAASI1VhEiLRZhIic5Iice4AAAAAOjU+///i0WESJhIicFID69N
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
QkktdGFnAC5ub3RlLmdudS5idWlsZC1pZAAuZ251Lmhhc2gALmR5bnN5bQAuZHluc3RyAC5nbnUu
dmVyc2lvbgAuZ251LnZlcnNpb25fcgAucmVsYS5keW4ALnJlbGEucGx0AC5pbml0AC50ZXh0AC5m
aW5pAC5yb2RhdGEALmVoX2ZyYW1lX2hkcgAuZWhfZnJhbWUALmN0b3JzAC5kdG9ycwAuamNyAC5k
eW5hbWljAC5nb3QALmdvdC5wbHQALmRhdGEALmJzcwAuY29tbWVudAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAB
AAAAAgAAAAAAAAAAAkAAAAAAAAACAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAA
AAATAAAABwAAAAIAAAAAAAAAHAJAAAAAAAAcAgAAAAAAACAAAAAAAAAAAAAAAAAAAAAEAAAAAAAA
AAAAAAAAAAAAIQAAAAcAAAACAAAAAAAAADwCQAAAAAAAPAIAAAAAAAAkAAAAAAAAAAAAAAAAAAAA
BAAAAAAAAAAAAAAAAAAAADQAAAD2//9vAgAAAAAAAABgAkAAAAAAAGACAAAAAAAAQAAAAAAAAAAF
AAAAAAAAAAgAAAAAAAAAAAAAAAAAAAA+AAAACwAAAAIAAAAAAAAAoAJAAAAAAACgAgAAAAAAANAC
AAAAAAAABgAAAAEAAAAIAAAAAAAAABgAAAAAAAAARgAAAAMAAAACAAAAAAAAAHAFQAAAAAAAcAUA
AAAAAAAHAQAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAE4AAAD///9vAgAAAAAAAAB4BkAA
AAAAAHgGAAAAAAAAPAAAAAAAAAAFAAAAAAAAAAIAAAAAAAAAAgAAAAAAAABbAAAA/v//bwIAAAAA
AAAAuAZAAAAAAAC4BgAAAAAAACAAAAAAAAAABgAAAAEAAAAIAAAAAAAAAAAAAAAAAAAAagAAAAQA
AAACAAAAAAAAANgGQAAAAAAA2AYAAAAAAABIAAAAAAAAAAUAAAAAAAAACAAAAAAAAAAYAAAAAAAA
AHQAAAAEAAAAAgAAAAAAAAAgB0AAAAAAACAHAAAAAAAA4AEAAAAAAAAFAAAADAAAAAgAAAAAAAAA
GAAAAAAAAAB+AAAAAQAAAAYAAAAAAAAAAAlAAAAAAAAACQAAAAAAABgAAAAAAAAAAAAAAAAAAAAE
AAAAAAAAAAAAAAAAAAAAeQAAAAEAAAAGAAAAAAAAABgJQAAAAAAAGAkAAAAAAABQAQAAAAAAAAAA
AAAAAAAABAAAAAAAAAAQAAAAAAAAAIQAAAABAAAABgAAAAAAAABwCkAAAAAAAHAKAAAAAAAAiAYA
AAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAACKAAAAAQAAAAYAAAAAAAAA+BBAAAAAAAD4EAAA
AAAAAA4AAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAkAAAAAEAAAACAAAAAAAAAAgRQAAA
AAAACBEAAAAAAACBAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAJgAAAABAAAAAgAAAAAA
AACMEUAAAAAAAIwRAAAAAAAALAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAACmAAAAAQAA
AAIAAAAAAAAAuBFAAAAAAAC4EQAAAAAAAKQAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAA
sAAAAAEAAAADAAAAAAAAAGASYAAAAAAAYBIAAAAAAAAQAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAA
AAAAAAAAALcAAAABAAAAAwAAAAAAAABwEmAAAAAAAHASAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAgA
AAAAAAAAAAAAAAAAAAC+AAAAAQAAAAMAAAAAAAAAgBJgAAAAAACAEgAAAAAAAAgAAAAAAAAAAAAA
AAAAAAAIAAAAAAAAAAAAAAAAAAAAwwAAAAYAAAADAAAAAAAAAIgSYAAAAAAAiBIAAAAAAACgAQAA
AAAAAAYAAAAAAAAACAAAAAAAAAAQAAAAAAAAAMwAAAABAAAAAwAAAAAAAAAoFGAAAAAAACgUAAAA
AAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAACAAAAAAAAADRAAAAAQAAAAMAAAAAAAAAMBRgAAAA
AAAwFAAAAAAAALgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAA2gAAAAEAAAADAAAAAAAA
AOgUYAAAAAAA6BQAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAOAAAAAIAAAA
AwAAAAAAAADwFGAAAAAAAOwUAAAAAAAAMAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAADl
AAAAAQAAADAAAAAAAAAAAAAAAAAAAADsFAAAAAAAAFoAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAEA
AAAAAAAAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAARhUAAAAAAADuAAAAAAAAAAAAAAAAAAAAAQAA
AAAAAAAAAAAAAAAAAA==" | openssl enc -d -base64 >$CACHEDIR/adlermap
	chmod 500 $CACHEDIR/adlermap
}
__exit() {
	local t pgid
	if [ -f /opt/fox_node/__node_config ]; then
		NODE_OS_TYPE="$(bash -c '. /opt/fox_node/__node_config; echo $NODE_OS_TYPE')"
		if [ -x /opt/fox_node/${NODE_OS_TYPE}/storage_wcache_zram_init ]; then
			read -r t t t t pgid t< /proc/self/stat
			/opt/fox_node/${NODE_OS_TYPE}/storage_wcache_zram_init nocache_remove_pid $pgid
			/opt/fox_node/${NODE_OS_TYPE}/storage_ssd_init nocache_remove_pid $pgid
		fi
	fi
	exit "$1"
	return 0
}
opt_pars "$@"
#

CACHEDIR=$HOME/.crb_cache
SCRIPT_DIR="$(readlink -nf ${0%/*})"
HASH_SIZE=8
[ -z "$BSIZE" ] && BSIZE=$((4*1024*1024)) # расчитано экспериментально для среднего образа жесткого диска

# расчетные переменные
SRC="$( opt_get 1 "$@" )" || true
DST="$( opt_get 2 "$@" )" || true

DST="$DST/"
DST="${DST//\/\///}"
[ -z "$SRC" -o -z "$DST" ] && { opt_usage "$0 [options] SRC DST"; exit 255; }

DST_DIR=${DST#*:}
DST_FILE=$DST_DIR/${SRC##*/}
DST_FILE_BMAP="$DST_DIR/.BMAP/${SRC##*/}.bmap"
DST_FILE_MODIFY="$DST_DIR/.BMAP/${SRC##*/}.dst_modify"
DST_FILE_SRC_MODIFY="$DST_DIR/.BMAP/${SRC##*/}.src_modify"
HASHBIN=$CACHEDIR/adlermap

if [ -f /opt/fox_node/__node_config ]; then
	NODE_OS_TYPE="$(bash -c '. /opt/fox_node/__node_config; echo $NODE_OS_TYPE')"
	if [ -x /opt/fox_node/${NODE_OS_TYPE}/storage_wcache_zram_init ]; then
		read -r t t t t pgid t< /proc/self/stat
		/opt/fox_node/${NODE_OS_TYPE}/storage_wcache_zram_init nocache_add_pid $pgid
		/opt/fox_node/${NODE_OS_TYPE}/storage_ssd_init nocache_add_pid $pgid
	fi
fi

# запускаем сервер на прием
if [ "$1" = '--server' ]; then
	do_server "$@"
	__exit $?
fi


set -e
set -u

# мы как утилита проверки и создания bmap
if [ $1 = '--recreate_dst_bmap' ]; then
	recreate_dst_bmap "$@"
	__exit $?
fi

# клиентскя часть
SRC="$(readlink -nf $SRC)"
# получим имя bmap конкретного DST root@www.example.com:/home/
if [ $IS_RECURSIVE != TRUE ]; then
	CACHE_BMAP=${DST//[:]/.}
	CACHE_BMAP=${CACHE_BMAP//[\/]/_}
	CACHE_BMAP=$CACHEDIR/$SRC/$CACHE_BMAP.bmap
	mkdir -p $CACHEDIR/$SRC/
	[ ! -f $CACHE_BMAP ] && touch $CACHE_BMAP

	SRC_FSIZE=$(stat -c "%s" $SRC)
	SRC_BCOUNT=$(((SRC_FSIZE-1) / BSIZE + 1)) #колво блоков
	# ploop not modify (( SRC_MODIFY=$(stat -c "%Z" $SRC)
	SRC_MODIFY=${DATESEC:-$(date +%s)}

	CACHE_BMAP_SIZE=$((((SRC_FSIZE-1)/BSIZE+1)*(HASH_SIZE+1)))

	[ ! -f "$SRC" ] && { echo "$SRC not found"; exit 255; }
	adlermap_create
fi
# проверяем надо ли нам вообще файл синхронизировать
# если файла нет, то надо
# если размер разный, то надо
# если дата src -gt dst, то надо

# если bmap нет, то надо и надо сделать bmap
# если dst старше, чем bmap, то надо и надо сделать bmap
# если размер bmap не равен размеру файла, то надо
__clean_old_format(){
	if $SSH -f "${DST_FILE}.bmap"; then
		$SSH rm -rf --one-file-system ${DST_FILE}.bmap ${DST_FILE}.h
	fi
}
__cmp_file_eq(){
	if [ "$(stat -c "%s" $SRC)" != $($SSH stat -c %s ${DST_FILE}) ] ; then
		echo "Размер $SRC!=$DST" >&2
		return 1
	fi
	if ! $SSH test -s ${DST_FILE_MODIFY}; then
		echo "Нет файла ${DST_FILE_MODIFY}" >&2
		return 1
	fi
	if ! $SSH test -s ${DST_FILE_SRC_MODIFY}; then
		echo "Нет файла ${DST_FILE_SRC_MODIFY}" >&2
		return 1
	fi
	if [ "$(stat -c "%Y" $SRC)" != $($SSH cat ${DST_FILE_SRC_MODIFY}) ]; then
		echo "Дата $SRC != ${DST_FILE_SRC_MODIFY}" >&2
		return 1
	fi
	if [ $($SSH stat -c %Y ${DST_FILE}) != $($SSH cat ${DST_FILE_MODIFY}) ]; then
		echo "Дата ${DST_FILE}!=${DST_FILE_MODIFY}" >&2
		return 1
	fi
	return 0
}

__valid_bmap(){
	if ! $SSH test -s "$DST_FILE_BMAP" ; then
		return 1
	fi
	DST_FILE_SIZE=$($SSH stat -c %s ${DST_FILE})
	DST_FILE_BMAP_SIZE=$($SSH stat -c %s ${DST_FILE_BMAP})
	DST_FILE_BLOCK_COUNT=$(((DST_FILE_SIZE-1)/BSIZE+1))
	DST_FILE_MAP_BLOCK_COUNT=$(($DST_FILE_BMAP_SIZE/9))
	if [ $DST_FILE_BLOCK_COUNT != $DST_FILE_MAP_BLOCK_COUNT ]; then
		echo "BLOCK_COUNT ${DST_FILE} != $DST_FILE_BMAP" >&2
		return 1
	fi
	if [ $($SSH stat -c %Y ${DST_FILE}) -gt  $($SSH stat -c %Y ${DST_FILE_BMAP}) ]; then
		echo "Дата ${DST_FILE} >= ${DST_FILE_BMAP}" >&2
		return 1
	fi
	return 0
}

SSH=eval

if [ "${DST_DIR:0:1}" != '/' ]; then
	echo "Относительные пути запрещены $DST_DIR '${DST_DIR:0:1}'!='/'"
	__exit 255
fi

if [[ "${DST}" = *:* ]]; then
	SSH_OPT="${SSH_OPT//,/ }"
	SSH_OPT="$SSH_OPT -oStrictHostKeyChecking=no -oControlPath=~/ssh_crab_cache_%r@%h"
	SSH_OPT="$SSH_OPT -oControlPersist=60 -oControlMaster=auto"
	SSH_OPT="$SSH_OPT -oServerAliveCountMax=3 -oServerAliveInterval=5"
	[[ "$SSH_OPT" == *'-i '* ]] && SSH_OPT="$SSH_OPT -oBatchMode=yes"
	SSH="ssh $SSH_OPT ${DST%%:*}"
	#scp $i $0 ${DST%%:*}:/$DST_DIR
	ssh $SSH_OPT ${DST%%:*} "mkdir -p /$DST_DIR/" # todo $SSH

	if [ "$IS_RECURSIVE" = TRUE ]; then
		ssh $SSH_OPT ${DST%%:*} "mkdir -p /$DST_DIR/.INFO/$RECUR_DATESEC/" # todo $SSH
		myip=$( ip r g 1 | head -n1 | awk '{printf $7}' )
		echo -n "$BK_LIST_FILE" \
			| ssh $SSH_OPT ${DST%%:*}\
			"dd conv=noerror,notrunc oflag=append of=/$DST_DIR/.INFO/$RECUR_DATESEC/file.list"
		echo "from $(hostname) $myip to ${DST%%:*}" \
			| ssh $SSH_OPT ${DST%%:*} \
			"dd conv=noerror of=/$DST_DIR/.INFO/$RECUR_DATESEC/info.txt"
		__exit 0
	fi
	cat $0 | ssh $SSH_OPT ${DST%%:*} "dd conv=noerror of=/$DST_DIR/.crab_sync"
	cat $HASHBIN | ssh $SSH_OPT ${DST%%:*} "dd conv=noerror of=/$DST_DIR/.hashbin; chmod +x /$DST_DIR/.hashbin"
	SERVER_CMD="$SSH /bin/bash /$DST_DIR/.crab_sync --server ""$@"
	SERVER_CMD_RECREATE_DST_BMAP="$SSH /bin/bash /$DST_DIR/.crab_sync --recreate_dst_bmap ""$@"
else
	mkdir -p /$DST_DIR/.INFO
	if [ "$IS_RECURSIVE" = TRUE ]; then
		mkdir -p /$DST_DIR/.INFO/$RECUR_DATESEC/
		myip=$( ip r g 1 | head -n1 | awk '{printf $7}' )
		echo -n "$BK_LIST_FILE" >> "/$DST_DIR/.INFO/$RECUR_DATESEC/file.list"
		echo "from $(hostname) $myip" > "/$DST_DIR/.INFO/$RECUR_DATESEC/info.txt"
		__exit 0
	fi
	cp -af $HASHBIN /$DST_DIR/.hashbin
	cp -af $0 /$DST_DIR/.crab_sync
	SERVER_CMD="$0 --server ""$@"
	SERVER_CMD_RECREATE_DST_BMAP="$0 --recreate_dst_bmap ""$@"
fi

sync_bmap(){
	echo todo cache bmap.md5
	$SSH /bin/cat "$DST_FILE_BMAP" > $CACHE_BMAP 2>/dev/null || touch  $CACHE_BMAP
}
if $SSH test -f ${DST_FILE}; then
	need_sync=1
	need_recreate_bmap=0
	if __cmp_file_eq; then
		need_sync=0
	else
		need_sync=1
	fi
	if __valid_bmap; then
		need_recreate_bmap=0
	else
		need_recreate_bmap=1
		need_sync=1
	fi
	if [ $need_sync = 0 ]; then
		echo "Файл $SRC не требует синхронизации" >&2
		__exit 0
	else
		echo "Файл $SRC требует синхронизации!"
	fi
	if [ $need_recreate_bmap = 1 ]; then
		echo "Файл $SRC требует перестройки bmap .0" >&2
		$SERVER_CMD_RECREATE_DST_BMAP
	fi
else
	echo "Файла нет $SRC -> ${DST_FILE}, требует копирования" >&2
	$SSH "rm -f $DST_FILE_BMAP"
fi
sync_bmap
if [[ "${DST}" = *:* ]]; then
	fstat_update2 "$DST_FILE"
	sync_file | lzop -1 -c | $SERVER_CMD
	if ! __cmp_file_eq; then
		echo "Файлы после синка имеют разный размер - форсируем перестройку bmap .1"
		$SERVER_CMD_RECREATE_DST_BMAP
		sync_bmap
		sync_file | lzop -1 -c | $SERVER_CMD
	fi
else
	fstat_update2 "$DST_FILE"
	sync_file | $SERVER_CMD
	if ! __cmp_file_eq; then
		echo "Файлы после синка имеют разный размер - форсируем перестройку bmap .2"
		$SERVER_CMD_RECREATE_DST_BMAP
		sync_bmap
		sync_file | $SERVER_CMD
	fi
fi
read -r FSEND < /tmp/fsend.$$
rm -f /tmp/fsend.$$
[ $SRC_FSIZE -lt $FSEND ] && FSEND=$SRC_FSIZE

echo "FSIZE=$SRC_FSIZE($((SRC_FSIZE/1024/1024))M) SEND=$FSEND($((FSEND/1024/1024))M)"\
	"time=$SECONDS speed=$((FSEND*10/1024/1024/(SECONDS*10+2)))M/sec"
echo '### crab_sync end ###'
#sync_file | $SERVER_CMD

#echo "123" | openssl enc -aes-128-cbc -k 123 | openssl enc -aes-128-cbc -k 123 -d

# тестирование o_direct
# размер блок мб	1	1ре	4	4ре
# из памяти sec		19	1	12	1
# direct адлер	sec	12	8	12	5
# direct адлер и dd sec	18	7	15	7
# ре - повторный синк

# тестирование сжатия
#чист	12	913408	
#ssh -c	50	222927	24%
#гзип	16	245038	26%
#лзоп	8	297733	32% 

# из двух бед меньшее берем, кеш не портим, но диск читаем 2 раза(стараемся рядом)
#todo adlermap читать по 8мб проеверять сразу тамже мап файл и выводить в стдаут
# готовый стринг и бинари


# идеи
#crab_sync Оптимальная скорость чтения без засирания кеша можно сделать через mmap private тк при закрытии файла кеш освобождается. adlermap нужно переписывать на си, чтобы он сам читал bmap использовал mmap private блоками по 500мб потом файл закрывается и блоки освобождаются, при несовпадении хеша адлер выводит нужную строку и данные на стдаут и это идет пайпом в ssh  crab_sync --serverf0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAcApAAAAAAABAAAAAAAAAABgWAAAAAAAAAAAAAEAAOAAI
__exit 0
exit 0
