From ee1b3473bbedb22cbd320fde5c29ea790722f7d0 Mon Sep 17 00:00:00 2001 From: deep-soft Date: Fri, 13 Oct 2023 16:37:31 +0300 Subject: [PATCH 1/4] Update setattr.cpp fix: FmtMask2 = L"99%c99%c9999N" and FmtMask3 = L"N9999%c99%c99"; without this in Attributes dialog (Ctrl+A) field year contains 5 digits number instead of 1 space and 4 digits. And because of this displayed date it's not correct, date "2023/10/13" is displayed as "20231/01/3 " --- far2l/src/setattr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/far2l/src/setattr.cpp b/far2l/src/setattr.cpp index f9e3199fd..07f8d239c 100644 --- a/far2l/src/setattr.cpp +++ b/far2l/src/setattr.cpp @@ -839,7 +839,7 @@ bool ShellSetFileAttributes(Panel *SrcPanel, LPCWSTR Object) wchar_t DateSeparator = GetDateSeparator(); wchar_t TimeSeparator = GetTimeSeparator(); wchar_t DecimalSeparator = GetDecimalSeparator(); - LPCWSTR FmtMask1 = L"99%c99%c99%c999", FmtMask2 = L"99%c99%c99999", FmtMask3 = L"99999%c99%c99"; + LPCWSTR FmtMask1 = L"99%c99%c99%c999", FmtMask2 = L"99%c99%c9999N", FmtMask3 = L"N9999%c99%c99"; FARString strDMask, strTMask; strTMask.Format(FmtMask1, TimeSeparator, TimeSeparator, DecimalSeparator); From 30e60810579390c1f5a6d579976c162e12456ffd Mon Sep 17 00:00:00 2001 From: deep-soft Date: Fri, 13 Oct 2023 20:13:59 +0300 Subject: [PATCH 2/4] Update setattr.cpp updated all 3 FmtMask FmtMask1 = L"99%c99%c99%c99N" FmtMask2 = L"99%c99%c9999N" FmtMask3 = L"N9999%c99%c99"; --- far2l/src/setattr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/far2l/src/setattr.cpp b/far2l/src/setattr.cpp index 07f8d239c..a2709122f 100644 --- a/far2l/src/setattr.cpp +++ b/far2l/src/setattr.cpp @@ -839,7 +839,7 @@ bool ShellSetFileAttributes(Panel *SrcPanel, LPCWSTR Object) wchar_t DateSeparator = GetDateSeparator(); wchar_t TimeSeparator = GetTimeSeparator(); wchar_t DecimalSeparator = GetDecimalSeparator(); - LPCWSTR FmtMask1 = L"99%c99%c99%c999", FmtMask2 = L"99%c99%c9999N", FmtMask3 = L"N9999%c99%c99"; + LPCWSTR FmtMask1 = L"99%c99%c99%c99N", FmtMask2 = L"99%c99%c9999N", FmtMask3 = L"N9999%c99%c99"; FARString strDMask, strTMask; strTMask.Format(FmtMask1, TimeSeparator, TimeSeparator, DecimalSeparator); From b9f9aa13f3c53c00593f4410554485dcf4d65ac0 Mon Sep 17 00:00:00 2001 From: deep-soft Date: Fri, 13 Oct 2023 20:16:48 +0300 Subject: [PATCH 3/4] Update filefilterparams.cpp fix: filefilterparams.cpp function bool FileFilterConfig(FileFilterParams *FF, bool ColorConfig) # ... switch (DateFormat) { # ... strDateMask.Format(L"99%c99%c9999N", DateSeparator, DateSeparator); # ... strDateMask.Format(L"99%c99%c9999N", DateSeparator, DateSeparator); # ... strDateMask.Format(L"N9999%c99%c99", DateSeparator, DateSeparator); # ... } # ... strTimeMask.Format(L"99%c99%c99%c99N", TimeSeparator, TimeSeparator, DecimalSeparator); # ... --- far2l/src/filefilterparams.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/far2l/src/filefilterparams.cpp b/far2l/src/filefilterparams.cpp index 5cbcfe32a..93e7af50e 100644 --- a/far2l/src/filefilterparams.cpp +++ b/far2l/src/filefilterparams.cpp @@ -801,20 +801,20 @@ bool FileFilterConfig(FileFilterParams *FF, bool ColorConfig) switch (DateFormat) { case 0: // Маска даты для форматов DD.MM.YYYYY и MM.DD.YYYYY - strDateMask.Format(L"99%c99%c99999", DateSeparator, DateSeparator); + strDateMask.Format(L"99%c99%c9999N", DateSeparator, DateSeparator); break; case 1: // Маска даты для форматов DD.MM.YYYYY и MM.DD.YYYYY - strDateMask.Format(L"99%c99%c99999", DateSeparator, DateSeparator); + strDateMask.Format(L"99%c99%c9999N", DateSeparator, DateSeparator); break; default: // Маска даты для формата YYYYY.MM.DD - strDateMask.Format(L"99999%c99%c99", DateSeparator, DateSeparator); + strDateMask.Format(L"N9999%c99%c99", DateSeparator, DateSeparator); break; } // Маска времени - strTimeMask.Format(L"99%c99%c99%c999", TimeSeparator, TimeSeparator, DecimalSeparator); + strTimeMask.Format(L"99%c99%c99%c99N", TimeSeparator, TimeSeparator, DecimalSeparator); DialogDataEx FilterDlgData[] = { {DI_DOUBLEBOX, 3, 1, 84, 18, {}, DIF_SHOWAMPERSAND, Msg::FileFilterTitle }, From 1d6b8b83c1357afae58f828b8ddf507c6ac20fec Mon Sep 17 00:00:00 2001 From: elfmz Date: Sat, 14 Oct 2023 01:19:33 +0300 Subject: [PATCH 4/4] NR/SHELL: refactoring and minor fixes --- NetRocks/CMakeLists.txt | 2 + NetRocks/src/Protocol/SHELL/Helpers/remote.sh | 201 +++++++++-------- NetRocks/src/Protocol/SHELL/ProtocolSHELL.cpp | 206 +++++++----------- NetRocks/src/Protocol/SHELL/ProtocolSHELL.h | 3 +- .../Protocol/SHELL/ProtocolSHELL_ExecCmd.cpp | 3 +- NetRocks/src/Protocol/SHELL/RemoteSh.cpp | 91 ++++++++ NetRocks/src/Protocol/SHELL/RemoteSh.h | 4 + NetRocks/src/Protocol/SHELL/Request.cpp | 34 +++ NetRocks/src/Protocol/SHELL/Request.h | 18 ++ NetRocks/src/Protocol/SHELL/WayToShell.cpp | 6 - NetRocks/src/Protocol/SHELL/WayToShell.h | 11 +- 11 files changed, 334 insertions(+), 245 deletions(-) create mode 100644 NetRocks/src/Protocol/SHELL/RemoteSh.cpp create mode 100644 NetRocks/src/Protocol/SHELL/RemoteSh.h create mode 100644 NetRocks/src/Protocol/SHELL/Request.cpp create mode 100644 NetRocks/src/Protocol/SHELL/Request.h diff --git a/NetRocks/CMakeLists.txt b/NetRocks/CMakeLists.txt index 0dcef3457..7e19fb04d 100644 --- a/NetRocks/CMakeLists.txt +++ b/NetRocks/CMakeLists.txt @@ -72,7 +72,9 @@ add_executable (NetRocks-SHELL src/Protocol/SHELL/ProtocolSHELL_ExecCmd.cpp src/Protocol/SHELL/WayToShellConfig.cpp src/Protocol/SHELL/WayToShell.cpp + src/Protocol/SHELL/Request.cpp src/Protocol/SHELL/Parse.cpp + src/Protocol/SHELL/RemoteSh.cpp src/Protocol/ShellParseUtils.cpp ) diff --git a/NetRocks/src/Protocol/SHELL/Helpers/remote.sh b/NetRocks/src/Protocol/SHELL/Helpers/remote.sh index b8ce85d0e..69a6f94b9 100755 --- a/NetRocks/src/Protocol/SHELL/Helpers/remote.sh +++ b/NetRocks/src/Protocol/SHELL/Helpers/remote.sh @@ -48,9 +48,7 @@ SHELLFCN_GET_INFO_INNER() { else SHELLVAR_SELECTED_LS_ARGS=$SHELLVAR_LS_ARGS - if [ -n "$2" ]; then - SHELLVAR_SELECTED_LS_ARGS=$SHELLVAR_LS_ARGS_FOLLOW - fi + [ -n "$2" ] && SHELLVAR_SELECTED_LS_ARGS=$SHELLVAR_LS_ARGS_FOLLOW if [ -n "$5" ]; then ls -d $SHELLVAR_SELECTED_LS_ARGS "$1" | grep $SHELLVAR_GREP_ARGS '^[^cbt]' | ( $SHELLVAR_READ_FN $5; echo $y ) else @@ -66,97 +64,102 @@ SHELLFCN_GET_SIZE() { } SHELLFCN_GET_INFO() { - SHELLVAR_INFO=`SHELLFCN_GET_INFO_INNER "$@" 2>>$SHELLVAR_LOG` - if [ -n "$SHELLVAR_INFO" ]; then - echo "+OK:$SHELLVAR_INFO" + SHELLVAR_OUT=`SHELLFCN_GET_INFO_INNER "$@" 2>>$SHELLVAR_LOG` + if [ -n "$SHELLVAR_OUT" ]; then + echo "+OK:$SHELLVAR_OUT" else - SHELLVAR_ERROR=`SHELLFCN_GET_INFO_INNER "$@" 2>&1` - echo "+ERROR:$SHELLVAR_ERROR" + SHELLVAR_OUT=`SHELLFCN_GET_INFO_INNER "$@" 2>&1` + echo "+ERROR:$SHELLVAR_OUT" fi } SHELLFCN_CMD_ENUM() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit if [ -n "$SHELLVAR_STAT" ]; then - stat --format="$SHELLVAR_STAT_FMT" "$SHELLVAR_ARG_PATH"/* "$SHELLVAR_ARG_PATH"/.* 2>>$SHELLVAR_LOG + stat --format="$SHELLVAR_STAT_FMT" "$SHELLVAR_ARG"/* "$SHELLVAR_ARG"/.* 2>>$SHELLVAR_LOG elif [ -n "$SHELLVAR_FIND" ]; then - find -H "$SHELLVAR_ARG_PATH" -mindepth 1 -maxdepth 1 -printf "$SHELLVAR_FIND_FMT" 2>>$SHELLVAR_LOG + find -H "$SHELLVAR_ARG" -mindepth 1 -maxdepth 1 -printf "$SHELLVAR_FIND_FMT" 2>>$SHELLVAR_LOG else - ls $SHELLVAR_LS_ARGS_FOLLOW "$SHELLVAR_ARG_PATH" 2>>$SHELLVAR_LOG | grep $SHELLVAR_GREP_ARGS '^[^cbt]' + ls $SHELLVAR_LS_ARGS_FOLLOW "$SHELLVAR_ARG" 2>>$SHELLVAR_LOG | grep $SHELLVAR_GREP_ARGS '^[^cbt]' fi } SHELLFCN_CMD_INFO_SINGLE() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit - SHELLFCN_GET_INFO "$SHELLVAR_ARG_PATH" "$1" "$2" "$3" "$4" + SHELLFCN_GET_INFO "$SHELLVAR_ARG" "$1" "$2" "$3" "$4" } SHELLFCN_CMD_INFO_MULTI() { # !!! This is a directory with symlinks listing bottleneck !!! # TODO: Rewrite so instead of querying files one-by-one do grouped queries with one stat per several files - while true; do - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit - [ ! -n "$SHELLVAR_ARG_PATH" ] && break - SHELLFCN_GET_INFO "$SHELLVAR_ARG_PATH" "$1" "$2" "$3" "$4" + while [ $SHELLVAR_ARG -gt 0 ]; do + $SHELLVAR_READ_FN SHELLVAR_PATH1 SHELLVAR_PATH2 SHELLVAR_PATH3 SHELLVAR_PATH4 SHELLVAR_PATH5 SHELLVAR_PATH6 SHELLVAR_PATH7 SHELLVAR_PATH8 || exit + [ $SHELLVAR_ARG -ge 1 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH1" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 2 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH2" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 3 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH3" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 4 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH4" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 5 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH5" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 6 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH6" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 7 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH7" "$1" "$2" "$3" "$4" + [ $SHELLVAR_ARG -ge 8 ] && SHELLFCN_GET_INFO "$SHELLVAR_PATH8" "$1" "$2" "$3" "$4" + SHELLVAR_ARG=`expr $SHELLVAR_ARG - 8` done } SHELLFCN_CHOOSE_BLOCK() { # $1 - size want to write # $2 - position want to seek (so chosen block size will be its divider) - BLOCK=1 - [ $1 -ge 16 ] && [ `expr $2 % 16` -eq 0 ] && BLOCK=16 - [ $1 -ge 64 ] && [ `expr $2 % 64` -eq 0 ] && BLOCK=64 - [ $1 -ge 512 ] && [ `expr $2 % 512` -eq 0 ] && BLOCK=512 - [ $1 -ge 4096 ] && [ `expr $2 % 4096` -eq 0 ] && BLOCK=4096 - [ $1 -ge 65536 ] && [ `expr $2 % 65536` -eq 0 ] && BLOCK=65536 + SHELLVAR_BLOCK=1 + [ $1 -ge 16 ] && [ `expr $2 % 16` -eq 0 ] && SHELLVAR_BLOCK=16 + [ $1 -ge 64 ] && [ `expr $2 % 64` -eq 0 ] && SHELLVAR_BLOCK=64 + [ $1 -ge 512 ] && [ `expr $2 % 512` -eq 0 ] && SHELLVAR_BLOCK=512 + [ $1 -ge 4096 ] && [ `expr $2 % 4096` -eq 0 ] && SHELLVAR_BLOCK=4096 + [ $1 -ge 65536 ] && [ `expr $2 % 65536` -eq 0 ] && SHELLVAR_BLOCK=65536 } SHELLFCN_CMD_READ() { - $SHELLVAR_READ_FN OFFSET SHELLVAR_ARG_PATH || exit - SIZE=`SHELLFCN_GET_SIZE "$SHELLVAR_ARG_PATH"` - if [ ! -n "$SIZE" ]; then + $SHELLVAR_READ_FN SHELLVAR_OFFSET || exit + SHELLVAR_SIZE=`SHELLFCN_GET_SIZE "$SHELLVAR_ARG"` + if [ ! -n "$SHELLVAR_SIZE" ]; then echo '+FAIL' return fi SHELLVAR_STATE= if [ -n "$SHELLVAR_DD" ]; then while true; do - REMAIN=`expr $SIZE - $OFFSET` + SHELLVAR_REMAIN=`expr $SHELLVAR_SIZE - $SHELLVAR_OFFSET` $SHELLVAR_READ_FN SHELLVAR_STATE || exit if [ "$SHELLVAR_STATE" = 'abort' ]; then echo '+ABORTED' $SHELLVAR_READ_FN SHELLVAR_STATE || exit break fi - if [ $REMAIN -le 0 ]; then + if [ $SHELLVAR_REMAIN -le 0 ]; then echo '+DONE' $SHELLVAR_READ_FN SHELLVAR_STATE || exit break fi - SHELLFCN_CHOOSE_BLOCK $REMAIN $OFFSET - PIECE=$REMAIN - [ $PIECE -gt 8388608 ] && PIECE=8388608 - CNT=`expr $PIECE / $BLOCK` - PIECE=`expr $CNT '*' $BLOCK` - echo '+NEXT:'$PIECE - dd iflag=fullblock skip=`expr $OFFSET / $BLOCK` count=$CNT bs=$BLOCK if="${SHELLVAR_ARG_PATH}" 2>>$SHELLVAR_LOG + SHELLFCN_CHOOSE_BLOCK $SHELLVAR_REMAIN $SHELLVAR_OFFSET + SHELLVAR_PIECE=$SHELLVAR_REMAIN + [ $SHELLVAR_PIECE -gt 8388608 ] && SHELLVAR_PIECE=8388608 + CNT=`expr $SHELLVAR_PIECE / $SHELLVAR_BLOCK` + SHELLVAR_PIECE=`expr $CNT '*' $SHELLVAR_BLOCK` + echo '+NEXT:'$SHELLVAR_PIECE + dd iflag=fullblock skip=`expr $SHELLVAR_OFFSET / $SHELLVAR_BLOCK` count=$CNT bs=$SHELLVAR_BLOCK if="${SHELLVAR_ARG}" 2>>$SHELLVAR_LOG ERR=$? if [ $ERR -ne 0 ]; then - # its unknown how much data was actually read, so send $PIECE of zeroes followed with ERROR statement + # its unknown how much data was actually read, so send $SHELLVAR_PIECE of zeroes followed with ERROR statement # unless its client aborted transfer by sending CtrlC - [ "$SHELLVAR_STATE" = 'abort' ] || dd iflag=fullblock count=$CNT bs=$BLOCK if=/dev/zero 2>>$SHELLVAR_LOG + [ "$SHELLVAR_STATE" = 'abort' ] || dd iflag=fullblock count=$CNT bs=$SHELLVAR_BLOCK if=/dev/zero 2>>$SHELLVAR_LOG SHELLFCN_SEND_ERROR_AND_RESYNC "$ERR" break fi - OFFSET=`expr $OFFSET + $PIECE` + SHELLVAR_OFFSET=`expr $SHELLVAR_OFFSET + $SHELLVAR_PIECE` done - elif [ $OFFSET -eq 0 ]; then + elif [ $SHELLVAR_OFFSET -eq 0 ]; then # no dd? fallback to cat, if can $SHELLVAR_READ_FN SHELLVAR_STATE || exit - echo '+NEXT:'$SIZE - cat "$SHELLVAR_ARG_PATH" 2>>$SHELLVAR_LOG + echo '+NEXT:'$SHELLVAR_SIZE + cat "$SHELLVAR_ARG" 2>>$SHELLVAR_LOG echo '+DONE' $SHELLVAR_READ_FN SHELLVAR_STATE || exit @@ -170,16 +173,16 @@ SHELLFCN_WRITE_BY_DD() { # $2 - offset # $3 - file SHELLFCN_CHOOSE_BLOCK $1 $2 - DDCNT=`expr $1 / $BLOCK` - DDPIECE=`expr $DDCNT '*' $BLOCK` - DDSEEK=`expr $2 '/' $BLOCK` - dd iflag=fullblock seek=$DDSEEK count=$DDCNT bs=$BLOCK of="$3" 2>>$SHELLVAR_LOG - rv=$? - if [ $rv -eq 0 ] && [ $DDPIECE -ne $1 ]; then - SHELLFCN_WRITE_BY_DD `expr $1 - $DDPIECE` `expr $2 + $DDPIECE` "$3" - rv=$? + SHELLVAR_DDCNT=`expr $1 / $SHELLVAR_BLOCK` + SHELLVAR_DDPIECE=`expr $SHELLVAR_DDCNT '*' $SHELLVAR_BLOCK` + SHELLVAR_DDSEEK=`expr $2 '/' $SHELLVAR_BLOCK` + dd iflag=fullblock seek=$SHELLVAR_DDSEEK count=$SHELLVAR_DDCNT bs=$SHELLVAR_BLOCK of="$3" 2>>$SHELLVAR_LOG + RV=$? + if [ $RV -eq 0 ] && [ $SHELLVAR_DDPIECE -ne $1 ]; then + SHELLFCN_WRITE_BY_DD `expr $1 - $SHELLVAR_DDPIECE` `expr $2 + $SHELLVAR_DDPIECE` "$3" + RV=$? fi - return $rv + return $RV } SHELLFCN_WRITE_BY_HEAD() { @@ -218,33 +221,37 @@ SHELLFCN_WRITE_BY_BASE64() { } SHELLFCN_CMD_WRITE() { - $SHELLVAR_READ_FN OFFSET SHELLVAR_ARG_PATH || exit + $SHELLVAR_READ_FN SHELLVAR_OFFSET || exit if [ -n "$SHELLVAR_DD" ] || [ -n "$SHELLVAR_HEAD" ] || [ -n "$SHELLVAR_BASE64" ]; then SHELLFCN_WRITE=SHELLFCN_WRITE_BY_BASE64 [ -n "$SHELLVAR_HEAD" ] && SHELLFCN_WRITE=SHELLFCN_WRITE_BY_HEAD [ -n "$SHELLVAR_DD" ] && SHELLFCN_WRITE=SHELLFCN_WRITE_BY_DD - if ! [ -n "$SHELLVAR_DD" ] && [ $OFFSET -ne 0 ] && ! truncate --size="$OFFSET" "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 ; then + if ! [ -n "$SHELLVAR_DD" ] && [ $SHELLVAR_OFFSET -ne 0 ] && ! truncate --size="$SHELLVAR_OFFSET" "$SHELLVAR_ARG" >>$SHELLVAR_LOG 2>&1 ; then SHELLFCN_SEND_ERROR_AND_RESYNC "$?" # avoid futher writings - SHELLVAR_ARG_PATH=/dev/null + SHELLVAR_ARG=/dev/null else echo '+OK' fi NSEQ=1 while true; do while true; do - $SHELLVAR_READ_FN SEQ SIZE || exit - [ "$SIZE" = '' ] || break + $SHELLVAR_READ_FN SEQ SHELLVAR_SIZE || exit + [ "$SHELLVAR_SIZE" = '' ] || break done - [ "$SEQ" = '.' ] && break - if [ $NSEQ -eq $SEQ ] && $SHELLFCN_WRITE $SIZE $OFFSET "$SHELLVAR_ARG_PATH"; then + if [ "$SEQ" = '.' ]; then + # have to create/truncate file if there was no data written + [ $NSEQ -eq 1 ] && ( touch "$SHELLVAR_ARG"; truncate --size="$SHELLVAR_OFFSET" "$SHELLVAR_ARG" ) >>$SHELLVAR_LOG 2>&1 + break + fi + if [ $NSEQ -eq $SEQ ] && $SHELLFCN_WRITE $SHELLVAR_SIZE $SHELLVAR_OFFSET "$SHELLVAR_ARG"; then echo '+OK' - OFFSET=`expr $OFFSET + $SIZE` + SHELLVAR_OFFSET=`expr $SHELLVAR_OFFSET + $SHELLVAR_SIZE` NSEQ=`expr $NSEQ + 1` else SHELLFCN_SEND_ERROR_AND_RESYNC "SEQ=$SEQ NSEQ=$NSEQ $?" # avoid futher writings - SHELLVAR_ARG_PATH=/dev/null + SHELLVAR_ARG=/dev/null fi done else @@ -253,33 +260,29 @@ SHELLFCN_CMD_WRITE() { } SHELLFCN_CMD_REMOVE_FILE() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit - unlink "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 || rm -f "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 + SHELLVAR_OUT=`unlink "$SHELLVAR_ARG" 2>&1 || rm -f "$SHELLVAR_ARG" 2>&1` RV=$? - [ $RV -ne 0 ] && echo "+ERROR:$RV" + [ $RV -ne 0 ] && echo "+ERROR:$SHELLVAR_OUT" } SHELLFCN_CMD_REMOVE_DIR() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit - rmdir "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 || rm -f "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 + SHELLVAR_OUT=`rmdir "$SHELLVAR_ARG" 2>&1 || rm -f "$SHELLVAR_ARG" 2>&1` RV=$? - [ $RV -ne 0 ] && echo "+ERROR:$RV" + [ $RV -ne 0 ] && echo "+ERROR:$SHELLVAR_OUT" } SHELLFCN_CMD_CREATE_DIR() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit $SHELLVAR_READ_FN SHELLVAR_ARG_MODE || exit - mkdir -m "$SHELLVAR_ARG_MODE" "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 + SHELLVAR_OUT=`mkdir -m "$SHELLVAR_ARG_MODE" "$SHELLVAR_ARG" 2>&1` RV=$? - [ $RV -ne 0 ] && echo "+ERROR:$RV" + [ $RV -ne 0 ] && echo "+ERROR:$SHELLVAR_OUT" } SHELLFCN_CMD_RENAME() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH1 || exit - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH2 || exit - mv "$SHELLVAR_ARG_PATH1" "$SHELLVAR_ARG_PATH2" >>$SHELLVAR_LOG 2>&1 + $SHELLVAR_READ_FN SHELLVAR_ARG_DEST || exit + SHELLVAR_OUT=`mv "$SHELLVAR_ARG" "$SHELLVAR_ARG_DEST" 2>&1` RV=$? - [ $RV -ne 0 ] && echo "+ERROR:$RV" + [ $RV -ne 0 ] && echo "+ERROR:$SHELLVAR_OUT" } SHELLFCN_READLINK_BY_LS() { @@ -301,38 +304,34 @@ SHELLFCN_READLINK_BY_LS() { } SHELLFCN_CMD_READ_SYMLINK() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH_LINK || exit - LNK=`$SHELLVAR_READLINK_FN "$SHELLVAR_ARG_PATH_LINK" 2>>$SHELLVAR_LOG` + SHELLVAR_OUT=`$SHELLVAR_READLINK_FN "$SHELLVAR_ARG" 2>>$SHELLVAR_LOG` RV=$? if [ $RV -eq 0 ]; then - echo "+OK:$LNK" + echo "+OK:$SHELLVAR_OUT" else - echo "+ERROR:$RV" + SHELLVAR_OUT=`$SHELLVAR_READLINK_FN "$SHELLVAR_ARG" 2>&1` + echo "+ERROR:$SHELLVAR_OUT" fi } SHELLFCN_CMD_MAKE_SYMLINK() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH_LINK || exit - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH_FILE || exit - ln -s "$SHELLVAR_ARG_PATH_FILE" "$SHELLVAR_ARG_PATH_LINK" >>$SHELLVAR_LOG 2>&1 + $SHELLVAR_READ_FN SHELLVAR_ARG_DEST || exit + SHELLVAR_OUT=`ln -s "$SHELLVAR_ARG_DEST" "$SHELLVAR_ARG" 2>&1` RV=$? - [ $RV -ne 0 ] && echo "+ERROR:$RV" + [ $RV -ne 0 ] && echo "+ERROR:$SHELLVAR_OUT" } SHELLFCN_CMD_SET_MODE() { - $SHELLVAR_READ_FN SHELLVAR_ARG_PATH || exit $SHELLVAR_READ_FN SHELLVAR_ARG_MODE || exit - chmod "$SHELLVAR_ARG_MODE" "$SHELLVAR_ARG_PATH" >>$SHELLVAR_LOG 2>&1 + SHELLVAR_OUT=`chmod "$SHELLVAR_ARG_MODE" "$SHELLVAR_ARG" 2>&1` RV=$? - [ $RV -ne 0 ] && echo "+ERROR:$RV" + [ $RV -ne 0 ] && echo "+ERROR:$SHELLVAR_OUT" } SHELLFCN_CMD_EXECUTE() { - $SHELLVAR_READ_FN SHELLVAR_ARG_CMD || exit - $SHELLVAR_READ_FN SHELLVAR_ARG_WD || exit - $SHELLVAR_READ_FN SHELLVAR_ARG_TOKEN || exit + $SHELLVAR_READ_FN SHELLVAR_ARG_TOKEN SHELLVAR_ARG_WD || exit if cd "$SHELLVAR_ARG_WD"; then - eval $SHELLVAR_ARG_CMD + eval $SHELLVAR_ARG RV=$? echo;echo "$SHELLVAR_ARG_TOKEN:$RV" else @@ -422,24 +421,24 @@ fi #SHELLVAR_BASE64= #echo "SHELLVAR_LS_ARGS=$SHELLVAR_LS_ARGS" -FEATS= +SHELLVAR_FEATS= if [ -n "$SHELLVAR_STAT" ]; then - FEATS="${FEATS}STAT " + SHELLVAR_FEATS="${SHELLVAR_FEATS}STAT " elif [ -n "$SHELLVAR_FIND" ]; then - FEATS="${FEATS}FIND " + SHELLVAR_FEATS="${SHELLVAR_FEATS}FIND " else - FEATS="${FEATS}LS " + SHELLVAR_FEATS="${SHELLVAR_FEATS}LS " fi if [ -n "$SHELLVAR_DD" ]; then - FEATS="${FEATS}READ_RESUME WRITE_RESUME " + SHELLVAR_FEATS="${SHELLVAR_FEATS}READ_RESUME WRITE_RESUME " elif [ -n "$SHELLVAR_HEAD" ]; then - FEATS="${FEATS}READ WRITE_RESUME " - [ -n "$SHELLVAR_WRITE_BLOCK" ] && FEATS="${FEATS}WRITE_BLOCK=$SHELLVAR_WRITE_BLOCK " + SHELLVAR_FEATS="${SHELLVAR_FEATS}READ WRITE_RESUME " + [ -n "$SHELLVAR_WRITE_BLOCK" ] && SHELLVAR_FEATS="${SHELLVAR_FEATS}WRITE_BLOCK=$SHELLVAR_WRITE_BLOCK " elif [ -n "$SHELLVAR_BASE64" ]; then - FEATS="${FEATS}READ WRITE_RESUME WRITE_BASE64 " + SHELLVAR_FEATS="${SHELLVAR_FEATS}READ WRITE_RESUME WRITE_BASE64 " else - FEATS="${FEATS}READ " + SHELLVAR_FEATS="${SHELLVAR_FEATS}READ " fi echo;echo;echo; @@ -447,9 +446,9 @@ SHELLVAR_NOPROMPT= while true; do [ ! -n "$SHELLVAR_NOPROMPT" ] && echo && echo '>(((^>' SHELLVAR_NOPROMPT= - $SHELLVAR_READ_FN CMD || exit - case "$CMD" in - feats ) echo "FEATS ${FEATS} SHELL.FAR2L";; + $SHELLVAR_READ_FN SHELLVAR_CMD SHELLVAR_ARG || exit + case "$SHELLVAR_CMD" in + feats ) echo "FEATS ${SHELLVAR_FEATS} SHELL.FAR2L";; enum ) SHELLFCN_CMD_ENUM;; linfo ) SHELLFCN_CMD_INFO_SINGLE '0' "$SHELLVAR_STAT_FMT_INFO" "$SHELLVAR_FIND_FMT_INFO" '';; info ) SHELLFCN_CMD_INFO_SINGLE '1' "$SHELLVAR_STAT_FMT_INFO" "$SHELLVAR_FIND_FMT_INFO" '';; @@ -478,6 +477,6 @@ while true; do # - lets mimic shell's responce so negotiation sequence will continue. # sleep 3 ensures 'fishy' prompt will be printed at the right time moment echo ) echo; echo 'far2l is ready for fishing'; sleep 3;; - * ) echo "Bad CMD='$CMD'" >>$SHELLVAR_LOG; echo "??? '$CMD'";; + * ) echo "Bad CMD='$SHELLVAR_CMD'" >>$SHELLVAR_LOG; echo "??? '$SHELLVAR_CMD'";; esac done diff --git a/NetRocks/src/Protocol/SHELL/ProtocolSHELL.cpp b/NetRocks/src/Protocol/SHELL/ProtocolSHELL.cpp index 57b1327e2..eb3bf9939 100644 --- a/NetRocks/src/Protocol/SHELL/ProtocolSHELL.cpp +++ b/NetRocks/src/Protocol/SHELL/ProtocolSHELL.cpp @@ -5,14 +5,14 @@ #include #include #include -#include #include "ProtocolSHELL.h" #include "WayToShellConfig.h" +#include "Request.h" #include "Parse.h" +#include "RemoteSh.h" #include #include -#include #include // для getenv #define GREETING_MSG "far2l is ready for fishing" @@ -45,60 +45,6 @@ static uint64_t GetIntegerBeforeStatusReplyLine(const std::string &data, size_t //////////////////////////// -static std::string LoadRemoteSh(const char *helper) -{ - std::ifstream helper_ifs; - helper_ifs.open(helper); - std::string out, tmp_str, varname; - if (!helper_ifs.is_open() ) { - throw ProtocolError("can't open helper", helper, errno); - } - std::map renamed_vars; - size_t orig_len = 0; - while (std::getline(helper_ifs, tmp_str)) { - orig_len+= tmp_str.size() + 1; - // do some compactization - StrTrim(tmp_str); -#if 1 - // skip no-code lines unless enabled logging (to keep line numbers) - if (tmp_str.empty() || tmp_str.front() == '#') { - if (g_netrocks_verbosity <= 0) { - continue; - } - tmp_str.clear(); - } - // rename variables - for (;;) { - size_t p = tmp_str.find("SHELLVAR_"); - if (p == std::string::npos) { - p = tmp_str.find("SHELLFCN_"); - if (p == std::string::npos) { - break; - } - } - size_t e = p + 8; - while (e < tmp_str.size() && (isalnum(tmp_str[e]) || tmp_str[e] == '_')) { - ++e; - } - varname = tmp_str.substr(p, e - p); - auto ir = renamed_vars.emplace(varname, renamed_vars.size()); - tmp_str.replace(p, e - p, StrPrintf("F%x", ir.first->second)); - } -#endif - out+= ' '; // prepend each line with space to avoid history pollution (as HISTCONTROL=ignorespace) - out+= tmp_str; - out+= '\n'; - } - fprintf(stderr, "[SHELL] LoadHelper('%s'): %lu -> %lu bytes, %lu tokens renamed\n", - helper, (unsigned long)orig_len, (unsigned long)out.size(), (unsigned long)renamed_vars.size()); - if (g_netrocks_verbosity > 2) { - fprintf(stderr, "---\n"); - fprintf(stderr, "%s\n", out.c_str()); - fprintf(stderr, "---\n"); - } - return out; -} - void ProtocolSHELL::SubstituteCreds(std::string &str) { Substitute(str, "$HOST", _host); @@ -229,7 +175,7 @@ void ProtocolSHELL::Initialize() auto wr = _way->SendAndWaitReply(LoadRemoteSh("SHELL/remote.sh"), s_prompt); fprintf(stderr, "[SHELL] REMOTE READY\n"); - wr = _way->SendAndWaitReply("feats\n", s_prompt); + wr = _way->SendAndWaitReply("feats .\n", s_prompt); if (wr.stdout_lines.size() > 1) { for (size_t i = wr.stdout_lines.size() - 1; i--; ) { //INFO ${INFO} SHELL.FAR2L @@ -294,21 +240,37 @@ void ProtocolSHELL::KeepAlive(const std::string &path_to_check) } } if (!_exec_cmd) { - _way->SendAndWaitReply("noop\n", s_prompt); + _way->SendAndWaitReply("noop .\n", s_prompt); } } void ProtocolSHELL::GetModes(bool follow_symlink, size_t count, const std::string *pathes, mode_t *modes) noexcept { - fprintf(stderr, "[SHELL] ProtocolSHELL::GetModes follow_symlink=%d count=%lu\n", follow_symlink, (unsigned long)count); - try { + if (count) try { FinalizeExecCmd(); - std::string request = follow_symlink ? "modes\n" : "lmodes\n"; - for (size_t i = 0; i != count; ++i) { - request+= pathes[i]; - request+= '\n'; + fprintf(stderr, "[SHELL] ProtocolSHELL::GetModes follow_symlink=%d count=%lu\n", follow_symlink, (unsigned long)count); + Request request(follow_symlink ? "modes " : "lmodes "); + request.AddFmt("%lu\n", (unsigned long)count); + for (size_t i = 0; i < count;) { + switch (std::min(count - i, (size_t)8)) { + case 8: request.Add(pathes[i++], ' '); + // fallthrough + case 7: request.Add(pathes[i++], ' '); + // fallthrough + case 6: request.Add(pathes[i++], ' '); + // fallthrough + case 5: request.Add(pathes[i++], ' '); + // fallthrough + case 4: request.Add(pathes[i++], ' '); + // fallthrough + case 3: request.Add(pathes[i++], ' '); + // fallthrough + case 2: request.Add(pathes[i++], ' '); + // fallthrough + case 1: request.Add(pathes[i++], '\n'); + break; + } } - request+= '\n'; auto wr = _way->SendAndWaitReply(request, s_prompt); ASSERT(wr.stdout_lines.size()); for (size_t i = count, j = wr.stdout_lines.size() - 1; i && j;) { @@ -335,11 +297,14 @@ void ProtocolSHELL::GetModes(bool follow_symlink, size_t count, const std::strin } } -void ProtocolSHELL::GetSingleFileInfo(const std::string &path, const char *what) +void ProtocolSHELL::GetSingleFileInfo(const char *what, const std::string &path) { fprintf(stderr, "[SHELL] ProtocolSHELL::%s: %s for '%s'\n", __FUNCTION__, what, path.c_str()); FinalizeExecCmd(); - const auto &wr = _way->SendAndWaitReply(MultiLineRequest(what, path), s_prompt); + const auto &wr = _way->SendAndWaitReply( + Request(what).Add(path, '\n'), + s_prompt + ); size_t i = wr.stdout_lines.size(); if (i--) while (i--) { const auto &line = wr.stdout_lines[i]; @@ -361,7 +326,7 @@ void ProtocolSHELL::GetSingleFileInfo(const std::string &path, const char *what) mode_t ProtocolSHELL::GetMode(const std::string &path, bool follow_symlink) { - GetSingleFileInfo(path, follow_symlink ? "mode" : "lmode"); + GetSingleFileInfo(follow_symlink ? "mode " : "lmode ", path); if (_feats.using_stat || _feats.using_find) { return SHELLParseModeByStatOrFind(_single_line_info); @@ -371,7 +336,7 @@ mode_t ProtocolSHELL::GetMode(const std::string &path, bool follow_symlink) unsigned long long ProtocolSHELL::GetSize(const std::string &path, bool follow_symlink) { - GetSingleFileInfo(path, follow_symlink ? "size" : "lsize"); + GetSingleFileInfo(follow_symlink ? "size " : "lsize ", path); if (_feats.using_stat || _feats.using_find) { return SHELLParseSizeByStatOrFind(_single_line_info); @@ -381,7 +346,7 @@ unsigned long long ProtocolSHELL::GetSize(const std::string &path, bool follow_s void ProtocolSHELL::GetInformation(FileInformation &file_info, const std::string &path, bool follow_symlink) { - GetSingleFileInfo(path, follow_symlink ? "info" : "linfo"); + GetSingleFileInfo(follow_symlink ? "info " : "linfo ", path); if (_feats.using_stat || _feats.using_find) { SHELLParseInfoByStatOrFind(file_info, _single_line_info); @@ -390,59 +355,53 @@ void ProtocolSHELL::GetInformation(FileInformation &file_info, const std::string } } -void ProtocolSHELL::FileDelete(const std::string &path) +void ProtocolSHELL::SendAndWaitPromptOrError(const char *what, const std::string &request) { - fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); + fprintf(stderr, "[SHELL] ProtocolSHELL::%s - %s\n", __FUNCTION__, what); FinalizeExecCmd(); - auto wr = _way->SendAndWaitReply( - MultiLineRequest("rmfile", path), - s_prompt_or_error); + auto wr = _way->SendAndWaitReply(request, s_prompt_or_error); if (wr.index != 0) { _way->WaitReply(s_prompt); - throw ProtocolError("rmfile error"); + auto &line = (wr.output_type == STDERR) ? wr.stderr_lines.back() : wr.stdout_lines.back(); + StrTrim(line, " \t\r\n"); + if (StrStartsFrom(line, s_prefix_error)) { + line.erase(0, sizeof(s_prefix_error) - 1); + } + if (line.empty()) { + line = "failed"; + } + throw ProtocolError(what, line.c_str()); } } +void ProtocolSHELL::FileDelete(const std::string &path) +{ + SendAndWaitPromptOrError("rmfile", + Request("rmfile ").Add(path, '\n') + ); +} + void ProtocolSHELL::DirectoryDelete(const std::string &path) { - fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); - FinalizeExecCmd(); - auto wr = _way->SendAndWaitReply( - MultiLineRequest("rmdir", path), - s_prompt_or_error); - if (wr.index != 0) { - _way->WaitReply(s_prompt); - throw ProtocolError("rmdir error"); - } + SendAndWaitPromptOrError("rmdir", + Request("rmdir ").Add(path, '\n') + ); } void ProtocolSHELL::DirectoryCreate(const std::string &path, mode_t mode) { - fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); - FinalizeExecCmd(); - auto wr = _way->SendAndWaitReply( - MultiLineRequest("mkdir", path, StrPrintf("0%o", mode & 0777)), - s_prompt_or_error); - if (wr.index != 0) { - _way->WaitReply(s_prompt); - throw ProtocolError("mkdir error"); - } + SendAndWaitPromptOrError("mkdir", + Request("mkdir ").Add(path, '\n').AddFmt("0%o\n", mode & 0777) + ); } void ProtocolSHELL::Rename(const std::string &path_old, const std::string &path_new) { - fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); - FinalizeExecCmd(); - auto wr = _way->SendAndWaitReply( - MultiLineRequest("rename", path_old, path_new), - s_prompt_or_error); - if (wr.index != 0) { - _way->WaitReply(s_prompt); - throw ProtocolError("rename error"); - } + SendAndWaitPromptOrError("rename", + Request("rename ").Add(path_old, '\n').Add(path_new, '\n') + ); } - void ProtocolSHELL::SetTimes(const std::string &path, const timespec &access_time, const timespec &modification_time) { fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); @@ -451,33 +410,21 @@ void ProtocolSHELL::SetTimes(const std::string &path, const timespec &access_tim void ProtocolSHELL::SetMode(const std::string &path, mode_t mode) { - fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); - FinalizeExecCmd(); - auto wr = _way->SendAndWaitReply( - MultiLineRequest("chmod", path, StrPrintf("0%o", mode & 0777)), - s_prompt_or_error); - if (wr.index != 0) { - _way->WaitReply(s_prompt); - throw ProtocolError("chmod error"); - } + SendAndWaitPromptOrError("chmod", + Request("chmod ").Add(path, '\n').AddFmt("0%o\n", mode & 0777) + ); } void ProtocolSHELL::SymlinkCreate(const std::string &link_path, const std::string &link_target) { - fprintf(stderr, "[SHELL] ProtocolSHELL::%s\n", __FUNCTION__); - FinalizeExecCmd(); - auto wr = _way->SendAndWaitReply( - MultiLineRequest("mksym", link_path, link_target), - s_prompt_or_error); - if (wr.index != 0) { - _way->WaitReply(s_prompt); - throw ProtocolError("mksym error"); - } + SendAndWaitPromptOrError("mksym", + Request("mksym ").Add(link_path, '\n').Add(link_target, '\n') + ); } void ProtocolSHELL::SymlinkQuery(const std::string &link_path, std::string &link_target) { - GetSingleFileInfo(link_path, "rdsym"); + GetSingleFileInfo("rdsym ", link_path); link_target.swap(_single_line_info); } @@ -492,7 +439,10 @@ class SHELLDirectoryEnumer : public IDirectoryEnumer { SHELLDirectoryEnumer(std::shared_ptr &app, const std::string &path, const RemoteFeats &feats) : _way(app) { - auto wr = _way->SendAndWaitReply( MultiLineRequest("enum", path), s_prompt_or_error); + auto wr = _way->SendAndWaitReply( + Request("enum ").Add(path, '\n'), + s_prompt_or_error + ); if (wr.index != 0) { _way->WaitReply(s_prompt); throw ProtocolError("dir query error"); @@ -583,7 +533,9 @@ class SHELLFileReader : public IFileReader SHELLFileReader(std::shared_ptr &app, const std::string &path, unsigned long long resume_pos) : _way(app) { - _way->Send( MultiLineRequest("read", StrPrintf("%llu %s", resume_pos, path.c_str()), "cont")); + _way->Send( + Request("read ").Add(path, '\n').AddFmt("%llu\n", resume_pos).Add("cont", '\n') + ); } virtual ~SHELLFileReader() @@ -652,7 +604,9 @@ class SHELLFileWriter : public IFileWriter SHELLFileWriter(std::shared_ptr &app, const std::string &path, mode_t mode, unsigned long long size_hint, unsigned long long resume_pos, const RemoteFeats &feats) : _way(app), _feats(feats) { - _way->Send( MultiLineRequest("write", StrPrintf("%llu %s", resume_pos, path.c_str()))); + _way->Send( + Request("write ").Add(path, '\n').AddFmt("%llu\n", resume_pos) + ); ++_pending_replies; } diff --git a/NetRocks/src/Protocol/SHELL/ProtocolSHELL.h b/NetRocks/src/Protocol/SHELL/ProtocolSHELL.h index 9ae2ebcc2..8d169ee38 100644 --- a/NetRocks/src/Protocol/SHELL/ProtocolSHELL.h +++ b/NetRocks/src/Protocol/SHELL/ProtocolSHELL.h @@ -85,7 +85,8 @@ class ProtocolSHELL : public IProtocol void FinalizeExecCmd(); void Initialize(); - void GetSingleFileInfo(const std::string &path, const char *what); + void GetSingleFileInfo(const char *what, const std::string &path); + void SendAndWaitPromptOrError(const char *what, const std::string &request); public: ProtocolSHELL(const std::string &host, unsigned int port, const std::string &username, diff --git a/NetRocks/src/Protocol/SHELL/ProtocolSHELL_ExecCmd.cpp b/NetRocks/src/Protocol/SHELL/ProtocolSHELL_ExecCmd.cpp index a8fb09dbb..7c90bc20f 100644 --- a/NetRocks/src/Protocol/SHELL/ProtocolSHELL_ExecCmd.cpp +++ b/NetRocks/src/Protocol/SHELL/ProtocolSHELL_ExecCmd.cpp @@ -12,6 +12,7 @@ #include #include #include "ProtocolSHELL.h" +#include "Request.h" // very poor for now @@ -230,7 +231,7 @@ ProtocolSHELL::ExecCmd::ExecCmd(std::shared_ptr &way, const std::str _fderr = fderr; RandomStringAppend(_marker_track.marker, 32, 32, RNDF_ALNUM); - way->Send( MultiLineRequest("exec", command_line, working_dir, _marker_track.marker)); + way->Send( Request("exec ").Add(command_line, '\n').Add(_marker_track.marker, ' ').Add(working_dir, '\n')); _marker_track.marker.insert(0, 1, '\n'); _marker_track.marker.append(1, ':'); diff --git a/NetRocks/src/Protocol/SHELL/RemoteSh.cpp b/NetRocks/src/Protocol/SHELL/RemoteSh.cpp new file mode 100644 index 000000000..bfd8fe52d --- /dev/null +++ b/NetRocks/src/Protocol/SHELL/RemoteSh.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include "../../Erroring.h" +#include "RemoteSh.h" + +#define COMPACTIZE_REMOTE_SH + +class CompactizedTokens +{ + std::map _m; + std::string _out; + +public: + CompactizedTokens(char heading) : _out(1, heading) { } + + const std::string &Compactize(const std::string &token) + { + auto ir = _m.emplace(token, _m.size()); + size_t n = ir.first->second; + _out.resize(1); + while (n) { + const char c = 'a' + (n % (1 + 'z' - 'a')); + n/= (1 + 'z' - 'a'); + _out+= c; + } + return _out; + } + + size_t Count() const { return _m.size(); } +}; + +std::string LoadRemoteSh(const char *helper) +{ + std::ifstream helper_ifs; + helper_ifs.open(helper); + std::string out, tmp_str; + if (!helper_ifs.is_open() ) { + throw ProtocolError("can't open helper", helper, errno); + } + CompactizedTokens comp_funcs('F'), comp_vars('V'); + size_t orig_len = 0; + while (std::getline(helper_ifs, tmp_str)) { + orig_len+= tmp_str.size() + 1; + // do some compactization + StrTrim(tmp_str); +#ifdef COMPACTIZE_REMOTE_SH + // skip no-code lines unless enabled logging (to keep line numbers) + if (tmp_str.empty() || tmp_str.front() == '#') { + if (g_netrocks_verbosity <= 0) { + continue; + } + tmp_str.clear(); + } + // rename tokens named for compactization + for (;;) { + CompactizedTokens *ct; + size_t p = tmp_str.find("SHELLVAR_"); + if (p == std::string::npos) { + p = tmp_str.find("SHELLFCN_"); + if (p == std::string::npos) { + break; + } + ct = &comp_funcs; + } else { + ct = &comp_vars; + } + size_t e = p + 9; + while (e < tmp_str.size() && (isalnum(tmp_str[e]) || tmp_str[e] == '_')) { + ++e; + } + tmp_str.replace(p, e - p, ct->Compactize(tmp_str.substr(p, e - p))); + } +#endif + out+= ' '; // prepend each line with space to avoid history pollution (as HISTCONTROL=ignorespace) + out+= tmp_str; + out+= '\n'; + } + fprintf(stderr, "[SHELL] %s('%s'): %lu -> %lu bytes, renamed %lu funcs and %lu vars\n", + __FUNCTION__, helper, (unsigned long)orig_len, (unsigned long)out.size(), + (unsigned long)comp_funcs.Count(), (unsigned long)comp_vars.Count()); + if (g_netrocks_verbosity > 2) { + fprintf(stderr, "---\n"); + fprintf(stderr, "%s\n", out.c_str()); + fprintf(stderr, "---\n"); + } + return out; +} + diff --git a/NetRocks/src/Protocol/SHELL/RemoteSh.h b/NetRocks/src/Protocol/SHELL/RemoteSh.h new file mode 100644 index 000000000..9b80acfdf --- /dev/null +++ b/NetRocks/src/Protocol/SHELL/RemoteSh.h @@ -0,0 +1,4 @@ +#pragma once +#include + +std::string LoadRemoteSh(const char *helper); diff --git a/NetRocks/src/Protocol/SHELL/Request.cpp b/NetRocks/src/Protocol/SHELL/Request.cpp new file mode 100644 index 000000000..44db0c4c8 --- /dev/null +++ b/NetRocks/src/Protocol/SHELL/Request.cpp @@ -0,0 +1,34 @@ +#include +#include "Request.h" + +Request::Request(const char *cmd_ending) + : _request(cmd_ending) +{ +} + +Request &Request::Add(const std::string &arg, char ending) +{ + for (size_t ofs = 0; ofs < arg.size();) { + const size_t p = arg.find_first_of(" \t\r\n\\", ofs); + if (p == std::string::npos) { + _request.append(arg.data() + ofs, arg.size() - ofs); + break; + } + _request.append(arg.data() + ofs, p - ofs); + _request+= '\\'; + _request+= arg[p]; + ofs = p + 1; + } + + _request+= ending; + return *this; +} + +Request &Request::AddFmt(const char *fmt_ending, ...) +{ + va_list args; + va_start(args, fmt_ending); + _request+= StrPrintfV(fmt_ending, args); + va_end(args); + return *this; +} diff --git a/NetRocks/src/Protocol/SHELL/Request.h b/NetRocks/src/Protocol/SHELL/Request.h new file mode 100644 index 000000000..5cb90a47f --- /dev/null +++ b/NetRocks/src/Protocol/SHELL/Request.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +class Request +{ + std::string _request; + +public: + Request(const char *cmd_ending); // expecting ending at the end of cmd + Request &Add(const std::string &arg, char ending); // appends escaped arg and ending + Request &AddFmt(const char *cmd_ending, ...); // expecting ending inside and not escaped! + + inline operator const std::string &() const + { + return _request; + } +}; diff --git a/NetRocks/src/Protocol/SHELL/WayToShell.cpp b/NetRocks/src/Protocol/SHELL/WayToShell.cpp index a18bc7909..3bafa8e87 100644 --- a/NetRocks/src/Protocol/SHELL/WayToShell.cpp +++ b/NetRocks/src/Protocol/SHELL/WayToShell.cpp @@ -632,9 +632,3 @@ void WayToShell::ReadStdout(void *buffer, size_t len) DebugStr("STDOUT.BLOB", info); } } - -std::string MultiLineRequest(std::string line) -{ - line+= '\n'; - return line; -} diff --git a/NetRocks/src/Protocol/SHELL/WayToShell.h b/NetRocks/src/Protocol/SHELL/WayToShell.h index d08dddf5b..e26fb09f0 100644 --- a/NetRocks/src/Protocol/SHELL/WayToShell.h +++ b/NetRocks/src/Protocol/SHELL/WayToShell.h @@ -13,6 +13,7 @@ #include #include "WayToShellConfig.h" +#include "Request.h" enum OutputType { @@ -67,13 +68,3 @@ class WayToShell WaitResult WaitReply(const std::vector &expected_replies); WaitResult SendAndWaitReply(const std::string &send_str, const std::vector &expected_replies, bool hide_in_log = false); }; - -std::string MultiLineRequest(std::string line); - -template - std::string MultiLineRequest(std::string line, const std::string &line2, LinesT... other_lines) -{ - line+= '\n'; - line+= line2; - return MultiLineRequest(line, other_lines...); -}