michaellukashov / Far-NetBox

SFTP/SCP/FTP/FTPS/WebDAV/S3 client for Far Manager 3 (http://farmanager.com/)
https://forum.farmanager.com/viewtopic.php?t=6317
GNU General Public License v2.0
158 stars 52 forks source link

Невозможность нормального перемещения по папкам после реконнекта #244

Closed 9-11 closed 7 years ago

9-11 commented 7 years ago

Ошибка описана на форуме http://forum.farmanager.com/viewtopic.php?p=142449#p142449 Кратко: если происходит обрыв соединения и последующий реконнект, то ходить по папкам становится невозможно.

Ошибка заключается в том, что после реконнекта не удаляются незавершённые транзакции. Моё решение по исправлению бага - сбрасывать счётчик FInTransaction в функции void TTerminal::Reopen(intptr_t Params):

void TTerminal::Reopen(intptr_t Params) { ... bool PrevAutoReadDirectory = FAutoReadDirectory; +FInTransaction = 0; // reset transactions ...

Решение проверено для доступа по SSH/SCP, FTP. После него всё работает без нареканий.

VictorVG commented 7 years ago

Добро. Собрал:
FarNetBox-2.4.3.508_Far3_x64_Fix.zip , FarNetBox-2.4.3.508_Far3_x86_Fix.zip

diff: NetBox_2.4.2.508_Fix.diff.zip

--- ./src/core/Terminal.cpp Git-857e78a96670b29096e55a2daeaa8b44425ae903
+++ ./src/core/Terminal.cpp Tue Jul 04 23:37:15 2017
@@ -1452,6 +1452,7 @@
   bool PrevReadDirectoryPending = FReadDirectoryPending;
   DebugAssert(!FSuspendTransaction);
   bool PrevAutoReadDirectory = FAutoReadDirectory;
+  FInTransaction = 0; // reset transactions
   // here used to be a check for FExceptionOnFail being 0
   // but it can happen, e.g. when we are downloading file to execute it.
   // however I'm not sure why we mind having exception-on-fail enabled here
@@ -6963,4 +6964,3 @@
   }
   return Result;
 }
-
9-11 commented 7 years ago

Fixed

VictorVG commented 7 years ago

Спасибо за подсказку! Здорово помогла. Нужное место отыскал grep-ом ибо он мне в этом привычен, а дальше написал дифф и перепроверил благо случай подвернулся в виде провала питания обесточившего роутер с поднятым там pure-ftpd.

9-11 commented 7 years ago

После того как всё заработало, плагин у себя некоторое время не обновлял. Сейчас обновился на последнюю версию и вижу, что ошибка вернулась. Тикет переоткрыл. Для быстрого воспроизведения можно зайти на свой сервер по ssh (SCP), выполнить kill $$ и сделать реконнект. Как я понимаю, @michaellukashov не хочет терять транзакцию, с тем расчётом, что она будет освобождена "в правильном месте". По идее, если бы освобождение всегда происходило вовремя, то нам бы не пришлось заботиться об этом в функции TTerminal::Reopen. Поняв это, я нашёл место в коде, где транзакция не освобождается, и которое предлагаю пропатчить:

bool TWinSCPFileSystem::ExecuteCommand(const UnicodeString & Command) {     ...     +FTerminal->BeginTransaction();     {         SCOPE_EXIT         {             if (FTerminal->GetActive())             {                   -FTerminal->EndTransaction();                     UpdatePanel();             }             else             {                 RedrawPanel();                 RedrawPanel(true);             }         };

После этого можно выкинуть весь код связанный с ресетом транзакций в функции TTerminal::Reopen. Проверил у себя на SSH и FTP - такой вариант работает, да и выглядит более логично.

VictorVG commented 7 years ago

@9-11

Т.е. если я вас правильно понял минимум коментим в ./src/NetBox/WinSCPFileSystem.cpp:::893

--- ./src/NetBox/WinSCPFileSystem.cpp   Sat Aug 05 23:25:47 2017
+++ ./src/NetBox/WinSCPFileSystem.cpp   Tue Aug 08 23:56:57 2017
@@ -890,7 +890,7 @@
       {
         if (FTerminal->GetActive())
         {
-          FTerminal->EndTransaction();
+//          FTerminal->EndTransaction();
           UpdatePanel();
         }
         else

поскольку FTerminal->EndTransaction(); завершает транзакцию до момента обновления панели, что и вызывает ошибку?

9-11 commented 7 years ago

Сорри, мой косяк. Доформатировался... Вот правильная версия:

bool TWinSCPFileSystem::ExecuteCommand(const UnicodeString & Command) {     ...     FTerminal->BeginTransaction();     {         SCOPE_EXIT         {             +FTerminal->EndTransaction();             if (FTerminal->GetActive())             {                   -FTerminal->EndTransaction();                     UpdatePanel();             }             else             {                 RedrawPanel();                 RedrawPanel(true);             }         };

Смысл в том, что каждая запущенная транзакция должна быть в конце концов завершена. В случае реконнекта условие не отрабатывало, и транзакция никогда не завершалась. Это, в свою очередь, приводило к ошибке.

9-11 commented 7 years ago

Fixed

VictorVG commented 7 years ago

Тогда надо закрыть этот инц чтобы под ногами не путался.

z0hm commented 7 years ago

Заходим на фтп, запускаем поиск слова в файлах AltF7 с рекурсией по подкаталогам. Если в процессе поиска потеряется соединение (теряет NB на каждый чих - uT же в это время как качал, так и качает), то после реконекта выдаёт диалог о продолжении поиска, но на утвердительный ответ ничего не происходит - после восстановления соединения наступает амнезия, НБ не помнит, что он делал перед этим и что нужно делать.