2016-07-09 3 views
1

Из программы C++ можно ли проверить, перенаправляется ли stderr в stdout или наоборот? В основном я хочу знать, указывают ли эти два дескриптора файла на одно и то же место. Решения, специфичные для платформы, с использованием встроенных API-интерфейсов в порядке.Проверьте программу, если stderr перенаправлен на stdout

+1

Попробуйте GetFinalPathNameByHandle. Я не уверен, работает ли он на трубах или нет, но стоит попробовать. –

+0

@HarryJohnston Пробовал 'GetFinalPathNameByHandle' в Windows 7, и, к сожалению, он не работал для' GetStdHandle (STD_OUTPUT_HANDLE) '. Он потерпел неудачу, с 'GetLastError()' возвращающим 'ERROR_INVALID_HANDLE'. – usta

ответ

2

Linux, возможно, другие unix-понравятся: fstat и fds и сравнить dev: ino pairs.

+0

Это, кажется, хорошо работает для моих нужд, спасибо! Теперь мне просто нужно решение для Windows ... – usta

1

для окон 7 и более поздних консольных ручек - это настоящие файловые дескрипторы (на XP это не правда, про Vista - не помню). мы можем получить эту 2 ручки по телефону GetStdHandle с STD_OUTPUT_HANDLE и STD_ERROR_HANDLE. но затем нужно как-то сравнить файлы с помощью дескриптора. это не равное прямое сравнение обрабатывает значения - потому что две разные ручки могут указывать на один и тот же файл. даже если мы получили указатель на FILE_OBJECT из дескриптора (это возможно из пользовательского режима) - два разных файла FILE_OBJECT могут указывать на один и тот же файл (если говорить о файлах файловой системы). так что лучший способ здесь, я думаю, - получить имена обоих файлов - и сравнить - они равны. это может быть сделано ZwQueryObject. код может быть, как это

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); 

но хр это будет не работать

+0

Спасибо! Наконец, я должен скомпилировать и связать этот код с Windows 7, но, к сожалению, он не работает по желанию. Даже при запуске программы с '2> & 1', имена различаются, например. '\ REGISTRY \ MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execut' ... для stdout и' \ KnownDlls' ... для stderr. Этот код работает по вашему желанию? – usta

+0

Также, когда данный дескриптор является трубой, то есть когда выход программы перенаправляется во вход другой программы, 'NtQueryObject()' терпит неудачу с 'STATUS_OBJECT_PATH_INVALID' (0xc0000039). – usta

+0

@usta - конечно этот код работа. и NtQueryObject не может вернуть STATUS_OBJECT_PATH_INVALID – RbMm

Смежные вопросы