Explorar o código

Bug 1694: Optionally consider exit code 1 an error when executing a shell command on a server

https://winscp.net/tracker/1694

Source commit: 9532d0f403822a83785e51b6dbd07a46c52dd62e
Martin Prikryl %!s(int64=7) %!d(string=hai) anos
pai
achega
1c4def2d13

+ 10 - 4
source/core/ScpFileSystem.cpp

@@ -25,10 +25,12 @@ const int coWaitForLastLine = 4;
 const int coOnlyReturnCode = 8;
 const int coIgnoreWarnings = 16;
 const int coReadProgress = 32;
+const int coIgnoreStdErr = 64;
 
 const int ecRaiseExcept = 1;
 const int ecIgnoreWarnings = 2;
 const int ecReadProgress = 4;
+const int ecIgnoreStdErr = 8;
 const int ecDefault = ecRaiseExcept;
 //---------------------------------------------------------------------------
 DERIVE_EXT_EXCEPTION(EScpFileSkipped, ESkipFile);
@@ -641,7 +643,7 @@ void __fastcall TSCPFileSystem::ReadCommandOutput(int Params, const UnicodeStrin
       }
       else
       {
-        bool IsStdErrOnlyError = FLAGCLEAR(Params, coIgnoreWarnings);
+        bool IsStdErrOnlyError = (FLAGCLEAR(Params, coIgnoreWarnings) && FLAGCLEAR(Params, coIgnoreStdErr));
         bool WrongOutput = !Message.IsEmpty() && ((FOutput->Count == 0) || IsStdErrOnlyError);
         if (WrongOutput || WrongReturnCode)
         {
@@ -673,7 +675,8 @@ void __fastcall TSCPFileSystem::ExecCommand(const UnicodeString & Cmd, int Param
     coWaitForLastLine |
     FLAGMASK(FLAGSET(Params, ecRaiseExcept), coRaiseExcept) |
     FLAGMASK(FLAGSET(Params, ecIgnoreWarnings), coIgnoreWarnings) |
-    FLAGMASK(FLAGSET(Params, ecReadProgress), coReadProgress);
+    FLAGMASK(FLAGSET(Params, ecReadProgress), coReadProgress) |
+    FLAGMASK(FLAGSET(Params, ecIgnoreStdErr), coIgnoreStdErr);
 
   ReadCommandOutput(COParams, &CmdString);
 }
@@ -1356,8 +1359,11 @@ void __fastcall TSCPFileSystem::AnyCommand(const UnicodeString Command,
 
   try
   {
-    ExecCommand(fsAnyCommand, ARRAYOFCONST((Command)),
-      ecDefault | ecIgnoreWarnings);
+    int Params =
+      ecDefault |
+      (FTerminal->SessionData->ExitCode1IsError ? ecIgnoreStdErr : ecIgnoreWarnings);
+
+    ExecCommand(fsAnyCommand, ARRAYOFCONST((Command)), Params);
   }
   __finally
   {

+ 9 - 0
source/core/SessionData.cpp

@@ -211,6 +211,7 @@ void __fastcall TSessionData::Default()
   TrimVMSVersions = false;
   Shell = L""; //default shell
   ReturnVar = L"";
+  ExitCode1IsError = false;
   ClearAliases = true;
   UnsetNationalVars = true;
   ListingCommand = L"ls -la";
@@ -340,6 +341,7 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(Special); \
   PROPERTY(Selected); \
   PROPERTY(ReturnVar); \
+  PROPERTY(ExitCode1IsError); \
   PROPERTY(LookupUserGroups); \
   PROPERTY(EOLType); \
   PROPERTY(TrimVMSVersions); \
@@ -653,6 +655,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool PuttyI
   PostLoginCommands = Storage->ReadString(L"PostLoginCommands", PostLoginCommands);
 
   ReturnVar = Storage->ReadString(L"ReturnVar", ReturnVar);
+  ExitCode1IsError = Storage->ReadBool(L"ExitCode1IsError", ExitCode1IsError);
   LookupUserGroups = TAutoSwitch(Storage->ReadInteger(L"LookupUserGroups2", LookupUserGroups));
   EOLType = (TEOLType)Storage->ReadInteger(L"EOLType", EOLType);
   TrimVMSVersions = Storage->ReadBool(L"TrimVMSVersions", TrimVMSVersions);
@@ -1021,6 +1024,7 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
     WRITE_DATA(String, PostLoginCommands);
 
     WRITE_DATA(String, ReturnVar);
+    WRITE_DATA(Bool, ExitCode1IsError);
     WRITE_DATA_EX(Integer, L"LookupUserGroups2", LookupUserGroups, );
     WRITE_DATA(Integer, EOLType);
     WRITE_DATA(Bool, TrimVMSVersions);
@@ -2727,6 +2731,11 @@ void __fastcall TSessionData::SetReturnVar(UnicodeString value)
 {
   SET_SESSION_PROPERTY(ReturnVar);
 }
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetExitCode1IsError(bool value)
+{
+  SET_SESSION_PROPERTY(ExitCode1IsError);
+}
 //---------------------------------------------------------------------------
 void __fastcall TSessionData::SetLookupUserGroups(TAutoSwitch value)
 {

+ 3 - 0
source/core/SessionData.h

@@ -149,6 +149,7 @@ private:
   bool FSelected;
   TAutoSwitch FLookupUserGroups;
   UnicodeString FReturnVar;
+  bool FExitCode1IsError;
   bool FScp1Compatibility;
   UnicodeString FShell;
   UnicodeString FSftpServer;
@@ -304,6 +305,7 @@ private:
   void __fastcall SetTrimVMSVersions(bool value);
   void __fastcall SetLookupUserGroups(TAutoSwitch value);
   void __fastcall SetReturnVar(UnicodeString value);
+  void __fastcall SetExitCode1IsError(bool value);
   void __fastcall SetScp1Compatibility(bool value);
   void __fastcall SetShell(UnicodeString value);
   void __fastcall SetSftpServer(UnicodeString value);
@@ -565,6 +567,7 @@ public:
   __property bool TrimVMSVersions = { read = FTrimVMSVersions, write = SetTrimVMSVersions };
   __property TAutoSwitch LookupUserGroups = { read = FLookupUserGroups, write = SetLookupUserGroups };
   __property UnicodeString ReturnVar = { read = FReturnVar, write = SetReturnVar };
+  __property bool ExitCode1IsError = { read = FExitCode1IsError, write = SetExitCode1IsError };
   __property bool Scp1Compatibility = { read = FScp1Compatibility, write = SetScp1Compatibility };
   __property UnicodeString Shell = { read = FShell, write = SetShell };
   __property UnicodeString SftpServer = { read = FSftpServer, write = SetSftpServer };

+ 3 - 2
source/core/SessionInfo.cpp

@@ -1203,10 +1203,11 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
       ADF(L"Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s; Follow directory symlinks: %s",
         (BooleanToEngStr(Data->ClearAliases), BooleanToEngStr(Data->UnsetNationalVars),
          BooleanToEngStr(Data->ResolveSymlinks), BooleanToEngStr(Data->FollowDirectorySymlinks)));
-      ADF(L"LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
+      ADF(L"LS: %s, Ign LS warn: %s, Scp1 Comp: %s; Exit code 1 is error: %s",
         (Data->ListingCommand,
          BooleanToEngStr(Data->IgnoreLsWarnings),
-         BooleanToEngStr(Data->Scp1Compatibility)));
+         BooleanToEngStr(Data->Scp1Compatibility),
+         BooleanToEngStr(Data->ExitCode1IsError)));
     }
     if ((Data->FSProtocol == fsSFTP) || (Data->FSProtocol == fsSFTPonly))
     {