2016-07-09 7 views
1

Aus einem C++ - Programm, ist es möglich zu überprüfen, ob stderr in stdout umgeleitet wird oder umgekehrt? Grundsätzlich möchte ich wissen, ob diese beiden Dateideskriptoren auf den gleichen Ort zeigen. Plattformspezifische Lösungen, die native APIs verwenden, sind in Ordnung.Einchecken eines Programms, wenn stderr zu stdout umgeleitet wird

+1

Versuchen Sie werden arbeiten. Ich bin mir nicht sicher, ob es für Rohre funktioniert oder nicht, aber es ist einen Versuch wert. –

+0

@HarryJohnston Versuchte 'GetFinalPathNameByHandle' auf Windows 7, und leider funktionierte es nicht für' GetStdHandle (STD_OUTPUT_HANDLE) '. Es ist fehlgeschlagen, wobei 'GetLastError() '' ERROR_INVALID_HANDLE' zurückgegeben hat. – usta

Antwort

2

Linux, möglicherweise auch andere Unix-Likes: fstat beide Fds und vergleichen dev: ino-Paare.

+0

Das scheint gut für meine Bedürfnisse zu funktionieren, danke! Jetzt brauche ich nur eine Lösung für Windows ... – usta

1

für Windows 7 und höher Konsole Griffe - das ist echte Datei behandelt (auf XP ist dies nicht wahr, über Vista - nicht erinnern). Wir können diese 2 Handles durch Aufruf GetStdHandle mit STD_OUTPUT_HANDLE und STD_ERROR_HANDLE bekommen. aber dann muss man Dateien irgendwie mit handle vergleichen. Dieser ungleiche direkte Vergleich behandelt Werte - weil zwei verschiedene Handles auf dieselbe Datei zeigen können. selbst wenn wir einen Zeiger auf FILE_OBJECT von handle bekommen (dies ist möglich aus dem Benutzermodus) - zwei verschiedene FILE_OBJECTs können auf dieselbe Datei zeigen (wenn wir über Dateisystemdateien sprechen). so gut denke ich hier - habe Namen von beiden Dateien - und vergleichen - sind sie gleich. Dies kann durch ZwQueryObject erfolgen. Code kann wie dieser

NTSTATUS QueryName(HANDLE hFile, PUNICODE_STRING Name) 
{ 
    union { 
     PVOID buf; 
     POBJECT_NAME_INFORMATION poni; 
    }; 

    static volatile UCHAR guz; 
    PVOID stack = alloca(guz); 

    ULONG cb = 0, rcb = 512; 
    NTSTATUS status; 

    do 
    { 
     if (cb < rcb) 
     { 
      cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack); 
     } 

     if (0 <= (status = ZwQueryObject(hFile, ObjectNameInformation, buf, cb, &rcb))) 
     { 
      return RtlDuplicateUnicodeString(0, &poni->Name, Name); 
     } 

    } while (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW); 

    return status; 
} 

NTSTATUS AreFilesTheSame(HANDLE h1, HANDLE h2, PBOOL pb) 
{ 
    if (h1 == h2) 
    { 
     *pb = TRUE; 
     return STATUS_SUCCESS; 
    } 

    if (!h1 || !h2) 
    { 
     *pb = FALSE; 
     return STATUS_SUCCESS; 
    } 

    UNICODE_STRING name1, name2; 
    NTSTATUS status; 

    if (0 <= (status = QueryName(h1, &name1))) 
    { 
     if (0 <= (status = QueryName(h2, &name2))) 
     { 
      *pb = RtlEqualUnicodeString(&name1, &name2, TRUE); 
      RtlFreeUnicodeString(&name2); 
     } 
     RtlFreeUnicodeString(&name1); 
    } 

    return status; 
} 

BOOL b; 
AreFilesTheSame(GetStdHandle(STD_OUTPUT_HANDLE), GetStdHandle(STD_ERROR_HANDLE), &b); 

sein, aber für xp wird dies nicht GetFinalPathNameByHandle

+0

Danke! Ich habe diesen Code unter Windows 7 kompiliert und verlinkt, aber leider funktioniert es nicht wie gewünscht. Selbst wenn das Programm mit "2> & 1" gestartet wird, sind die Namen unterschiedlich, z. '\ REGISTRY \ MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ AktuelleVersion \ Image File Execut' ... für stdout vs.' \ KnownDlls' ... für stderr. Funktioniert dieser Code wie gewünscht für Sie? – usta

+0

Auch wenn ein gegebenes Handle eine Pipe ist, d.h. wenn die Ausgabe des Programms in die Eingabe eines anderen Programms umgeleitet wird, schlägt 'NtQueryObject()' mit 'STATUS_OBJECT_PATH_INVALID' (0xc0000039) fehl. – usta

+0

@usta - natürlich funktioniert dieser Code. und NtQueryObject kann nicht STATUS_OBJECT_PATH_INVALID – RbMm

Verwandte Themen