Skip to content

Commit

Permalink
Prevent hangup when reading ExifTool pipe fails
Browse files Browse the repository at this point in the history
  • Loading branch information
FrankBijnen committed Nov 5, 2024
1 parent 4bee96a commit 6f6a4d3
Showing 1 changed file with 24 additions and 9 deletions.
33 changes: 24 additions & 9 deletions Source/ExifTool_PipeStream.pas
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ TPipeStream = class(TBytesStream)
public
constructor Create(AFile: THandle; ABufSize: integer);
function PipeHasData: boolean;
function PipeHasReady(const ExecNum: word): boolean;
function PipeHasReadyOrFatal(const ExecNum: word): boolean;
procedure CheckFilesProcessed;
procedure ClearCounter;
procedure SetCounter(ACounter: TET_Counter);
Expand Down Expand Up @@ -64,13 +64,15 @@ TSOReadPipeThread = class(TThread)

implementation

uses System.SysUtils;
uses
System.SysUtils;

const
CR = 13;
LF = 10;
ReadyPrompt: Utf8string = '{ready';
FilePrompt: Utf8string = '========';
Fatal: Utf8string = '{Fatal}';
FilePrompt: Utf8string = '========';

constructor TPipeStream.Create(AFile: THandle; ABufSize: integer);
begin
Expand Down Expand Up @@ -148,7 +150,7 @@ function TPipeStream.PipeHasData: boolean;
end;

// Note: {Readynn} can occur on multiple lines, only the last line is checked!
function TPipeStream.PipeHasReady(const ExecNum: word): boolean;
function TPipeStream.PipeHasReadyOrFatal(const ExecNum: word): boolean;
var StartPos, EndPos: PByte;
ReadyLine: UTF8String;
begin
Expand All @@ -160,7 +162,8 @@ function TPipeStream.PipeHasReady(const ExecNum: word): boolean;
exit(false);

ReadyLine := GetPipe(StartPos, EndPos);
result := (Pos(ReadyPrompt + IntToStr(ExecNum) + '}', ReadyLine) > 0);
result := (ReadyLine = Fatal) or
(Pos(ReadyPrompt + IntToStr(ExecNum) + '}', ReadyLine) > 0);
end;

// Scan for ===== (New file processed by ExifTool)
Expand Down Expand Up @@ -195,9 +198,21 @@ procedure TPipeStream.SetCounter(ACounter: TET_Counter);
end;

function TPipeStream.ReadPipe: DWORD;
var
FLastError: UTF8String;
begin
if (Winapi.Windows.ReadFile(HFile, FileBuffer[0], FBufSize, result, nil)) then
Self.Write(FileBuffer[0], result);
if (Winapi.Windows.ReadFile(HFile, FileBuffer[0], FBufSize, result, nil) = false) then
begin
// Write the ErrorMessage + {Fatal} in stream.
// Prevents hang when ExifTool does not write {Ready}. E.G. Perl aborts because compilation error
// PipeHasReadyOrFatal checks this.
FLastError := SysErrorMessage(GetLastError) + Chr(CR) + Chr(LF) + Fatal + Chr(CR) + Chr(LF);
Self.Write(FLastError[1], Length(FLastError));
exit(0); // Stop reading pipe
end;

Self.Write(FileBuffer[0], result);

if (result > 0) then
CheckFilesProcessed;
end;
Expand Down Expand Up @@ -239,8 +254,8 @@ function TPipeStream.AnalyseError: string;
end;

{ TReadPipeThread }
// Read Pipe in separate thread

// Read Pipe in separate thread
constructor TReadPipeThread.Create(AFile: THandle; ABufSize: integer);
begin
FPipeStream := TPipeStream.Create(AFile, ABufSize);
Expand Down Expand Up @@ -271,7 +286,7 @@ procedure TSOReadPipeThread.Execute;
begin
// Continue until we see our execnum
// -executexx and -echo4 CRLF xx need to be set for this to work
while (not FPipeStream.PipeHasReady(FExecNum)) do
while (not FPipeStream.PipeHasReadyOrFatal(FExecNum)) do
FPipeStream.ReadPipe;
end;

Expand Down

0 comments on commit 6f6a4d3

Please sign in to comment.