Jak sprawdzić, czy dany deskryptor pliku przechowywany w zmiennej jest nadal poprawny?

Mam deskryptor pliku przechowywany w zmiennej typu var. Jak mogę sprawdzić, czy ten deskryptor jest ważny na późniejszym etapie?

  fdvar1= open(.....);
  fdvar2 = fdvar1;       // Please ignore the bad design

  ....
  // lots of loops , conditionals and threads. It can call close(fdvar2) also.  
  ....

  if(CheckValid(fdvar1)) // How can I do this check  ?
    write(fdvar1, ....);

Teraz chcę sprawdzić, czy var1 (który nadal posiada otwarty deskryptor) jest nadal poprawny. Jakieś API do tego?

Author: Lunar Mushrooms, 2012-09-09

6 answers

fcntl(fd, F_GETFD) jest kanonicznym najtańszym sposobem sprawdzenia, czy fd jest prawidłowym deskryptorem otwartego pliku. Jeśli potrzebujesz dużo sprawdzać wsadowo, użycie poll z zerowym timeoutem i składnikiem events ustawionym na 0 i sprawdzanie POLLNVAL w revents po jego powrocie jest bardziej efektywne.

Z tym, że operacja "sprawdź, czy dany uchwyt zasobów jest nadal poprawny" jest prawie zawsze zasadniczo Niepoprawna. Po zwolnieniu obsługi zasobów (np. fd to close d), jego wartość może zostać przypisana do następny taki zasób przydzielisz. Jeśli istnieją jakieś Pozostałe odniesienia, które mogą być użyte, będą one nieprawidłowo działać na nowym zasobie, a nie na Starym. Tak więc, prawdziwa odpowiedź brzmi prawdopodobnie: jeśli nie znasz jeszcze logiki swojego programu, masz główne podstawowe błędy logiczne, które należy naprawić.

 64
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-15 00:02:54

Możesz użyć funkcji fcntl():

int fd_is_valid(int fd)
{
    return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
 21
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-09 16:20:02

Nie wydaje mi się, że istnieje jakaś funkcja, która może Ci powiedzieć, czy deskryptor jest nadal poprawny. Deskryptor jest zazwyczaj małą liczbą całkowitą, taką jak 6, A libc może wybrać ponowne użycie tej liczby, jeśli zamkniesz plik i otworzysz nowy później.

Zamiast tego powinieneś rozważyć użycie dup() do skopiowania deskryptora pliku. Powielając deskryptor pliku zamiast używać tego samego deskryptora w wielu miejscach, łatwiej będzie Ci dowiedzieć się, czy deskryptor pliku jest nadal ważne. Musisz tylko pamiętać, aby zamknąć zarówno oryginalny deskryptor, jak i powielony po zakończeniu.

 4
Author: David Grayson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-15 17:30:56

Z tego artykułu na forum:

int is_valid_fd(int fd)
{
    return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
}

Fcntl (GETFL) jest prawdopodobnie najtańszym i najmniej prawdopodobnym niepowodzeniem operacja, którą można wykonać na deskryptorze pliku. W szczególności Specyfikacja sugeruje, że nie może być przerwany przez sygnały, ani czy ma to wpływ na każdy rodzaj zamka trzymanego w dowolnym miejscu.

 3
Author: wbao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-09 22:29:37

Wydaje mi się, że jeśli chcesz wiedzieć, czy nadal wskazuje na ten sam zasób, jednym (Nie-idealnym) podejściem byłoby fstat() deskryptor tuż po otwarciu, a później możesz zrobić to ponownie i porównać wyniki. Zacznij od spojrzenia na .st_mode& S_IFMT i dalej ... czy to obiekt systemu plików? Spójrz na .st_dev / .st_ino. czy to gniazdo? Spróbuj getsockname(), getpeername(). Nie będzie to w 100% pewne, ale może powiedzieć, czy na pewno nie jest to samo.

 0
Author: John Hascall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-09 15:49:59

Rozwiązałem ten problem za mnie. Nie wiem czy da się go użyć do ogólnego przeznaczenia, ale dla połączeń szeregowych działa dobrze (np. /dev/ttyUSB0)!

struct stat s;
fstat(m_fileDescriptor, &s);

// struct stat::nlink_t   st_nlink;   ... number of hard links 
if( s.st_nlink < 1 ){
 // treat device disconnected case
}

Po szczegóły patrz np. strona man http://linux.die.net/man/2/fstat

Pozdrawiam, Flo
 -1
Author: flozn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-10 13:51:55