Ambil nama file dari deskriptor file di C


105

Apakah mungkin untuk mendapatkan nama file dari deskriptor file (Linux) di C?


Saya kira, jawaban yang dipilih harus diberikan kepada zneak karena solusinya memiliki portabilitas yang lebih baik dan tidak memiliki masalah akses.
Sergei

Itu tidak didukung di Ubuntu 14.04 (kernel 3.16.0-76-generic). Saya kira itu tidak didukung di Linux sama sekali.
felipou

Untuk macOS, lihat jawaban untuk pertanyaan lain oleh D. Nathanael ini .
Jonathan Leffler

Jawaban:


120

Anda dapat menggunakan readlinkdi /proc/self/fd/NNNmana NNN adalah deskriptor file. Ini akan memberi Anda nama file seperti saat dibuka - namun, jika file dipindahkan atau dihapus sejak saat itu, mungkin tidak lagi akurat (meskipun Linux dapat melacak penggantian nama dalam beberapa kasus). Untuk memverifikasi, statnama file yang diberikan dan fstatfd yang Anda miliki, dan pastikan st_devdan st_inosama.

Tentu saja, tidak semua deskriptor file merujuk ke file, dan untuk itu Anda akan melihat beberapa string teks yang aneh, seperti pipe:[1538488]. Karena semua nama file asli akan menjadi jalur absolut, Anda dapat menentukan mana yang cukup mudah. Lebih lanjut, seperti yang diketahui orang lain, file dapat memiliki beberapa hardlink yang mengarah ke mereka - ini hanya akan melaporkan hardlink yang dibukanya. Jika Anda ingin mencari semua nama untuk file tertentu, Anda hanya perlu melintasi seluruh sistem file.


9
Selama file asli masih memiliki referensi ke file tersebut (open fdakan menjadi referensi seperti itu), nomor inode tidak dapat digunakan kembali. Perangkat lunak apa pun yang menggunakan nomor inode setelah menutup file atau sebelum membukanya tunduk pada ketentuan balapan.
R .. GitHub STOP HELPING ICE

3
Bahaya, Akankah Robinson! Ini tidak selalu berhasil --- jika Anda melakukan setuid()trik, mungkin saja /proc/self/fdtidak dapat diakses oleh proses Anda. Lihat: permalink.gmane.org/gmane.linux.kernel/1302546
David Diberikan

2
@bdonlan: dan dalam kasus / proc tidak dipasang?
pengguna2284570

1
@ user2284570, jawaban ini khusus untuk Linux. Saya tidak tahu apakah NetBSD mendukung procfs sama sekali - jika host bersama Anda tidak menyediakannya, mungkin karena NetBSD tidak mendukungnya sama sekali dan menggunakan mekanisme lain sebagai gantinya. Anda mungkin ingin mengirim pertanyaan lain dengan fokus NetBSD untuk melihat apakah ada yang tahu bagaimana NetBSD memaparkan informasi ini (Anda mungkin juga ingin mencoba jawaban zneak di bawah ini, OS X lebih mirip dengan BSD daripada Linux)
bdonlan

1
@bdonlan: NetBSD support / proc tetapi tidak wajib untuk memasangnya. Setiap kali saya sebutkan, jawabannya menjadi "beralihlah ke penyedia biaya yang lebih tinggi dan Anda akan mendapatkan / proc". Jadi saya mencari solusi tanpa proses.
pengguna2284570

90

Saya mengalami masalah ini di Mac OS X. Kami tidak memiliki /procsistem file virtual, jadi solusi yang diterima tidak dapat berfungsi.

Kami, sebaliknya, memiliki F_GETPATHperintah untuk fcntl:

 F_GETPATH          Get the path of the file descriptor Fildes.  The argu-
                    ment must be a buffer of size MAXPATHLEN or greater.

Jadi untuk mendapatkan file yang terkait dengan deskriptor file, Anda dapat menggunakan cuplikan ini:

#include <sys/syslimits.h>
#include <fcntl.h>

char filePath[PATH_MAX];
if (fcntl(fd, F_GETPATH, filePath) != -1)
{
    // do something with the file path
}

Karena saya tidak pernah ingat di mana MAXPATHLENdidefinisikan, saya pikir PATH_MAXdari syslimits akan baik-baik saja.


@uchuugaka, mungkin tidak. Gunakan getsockname.
zneak

2
Apa yang kamu harapkan? Kecuali itu soket UNIX, itu tidak memiliki file yang terkait.
zneak

2
@uchuugaka Ya, semuanya adalah file, tetapi tidak semuanya adalah entri direktori dengan nama dan lokasi di dalam pohon sistem file. File diwakili oleh inode, itu bisa ada tanpa entri direktori yang merujuk padanya.
lgeorget

9
Dalam <sys / param.h>: #define MAXPATHLEN PATH_MAX
geowar

1
Saya baru saja menguji ini dan tetap benar jika file dipindahkan dan Anda memanggilnya lagi (artinya: Anda mendapatkan jalur baru dari file tersebut). Namun ini tidak didukung di linux (diuji di Ubuntu 14.04 - F_GETPATH ​​tidak ditentukan).
felipou


15

Seperti yang ditunjukkan Tyler, tidak ada cara untuk melakukan apa yang Anda perlukan "secara langsung dan andal", karena FD tertentu mungkin sesuai dengan 0 nama file (dalam berbagai kasus) atau> 1 (beberapa "tautan keras" adalah bagaimana situasi yang terakhir ini umumnya dijelaskan ). Jika Anda masih membutuhkan fungsionalitas dengan semua batasan (pada kecepatan DAN kemungkinan mendapatkan hasil 0, 2, ... daripada 1), berikut cara melakukannya: pertama, fstat FD - ini memberi tahu Anda , pada struct statperangkat apa file tersebut berada, berapa banyak tautan keras yang dimilikinya, apakah itu file khusus, dll. Ini mungkin sudah menjawab pertanyaan Anda - mis. jika 0 tautan keras Anda akan TAHU sebenarnya tidak ada nama file yang sesuai di disk.

Jika statistik memberi Anda harapan, maka Anda harus "berjalan di pohon" direktori pada perangkat yang relevan sampai Anda menemukan semua tautan keras (atau hanya yang pertama, jika Anda tidak membutuhkan lebih dari satu dan salah satu akan melakukannya ). Untuk tujuan itu, Anda menggunakan readdir (dan opendir & c tentu saja) membuka subdirektori secara rekursif sampai Anda menemukan struct direntinode yang menerima nomor inode yang sama dengan yang Anda miliki di aslinya struct stat(pada saat itu jika Anda menginginkan seluruh jalur, bukan hanya namanya, Anda harus berjalan ke belakang rantai direktori untuk merekonstruksinya).

Jika pendekatan umum ini dapat diterima, tetapi Anda memerlukan kode C yang lebih rinci, beri tahu kami, ini tidak akan sulit untuk menulis (meskipun saya lebih suka tidak menulisnya jika tidak berguna, yaitu Anda tidak dapat menahan kinerja lambat yang tak terelakkan atau kemungkinan mendapatkan! = 1 hasil untuk keperluan aplikasi Anda ;-).


9

Sebelum menulis ini karena tidak mungkin, saya sarankan Anda melihat kode sumber dari perintah lsof .

Mungkin ada batasan tetapi lsof tampaknya mampu menentukan deskriptor file dan nama file. Informasi ini ada di filesystem / proc sehingga dapat diakses dari program Anda.


6

Anda bisa menggunakan fstat () untuk mendapatkan inode file dengan status struct. Kemudian, menggunakan readdir () Anda dapat membandingkan inode yang Anda temukan dengan yang ada (struct dirent) di direktori (dengan asumsi Anda mengetahui direktori tersebut, jika tidak Anda harus mencari seluruh sistem file) dan menemukan nama file yang sesuai. Menjijikan?


2

Mustahil. Deskriptor file mungkin memiliki banyak nama dalam sistem file, atau mungkin tidak memiliki nama sama sekali.

Edit: Dengan asumsi Anda berbicara tentang sistem POSIX lama biasa, tanpa API khusus OS, karena Anda tidak menentukan OS.


4
maka jawaban saya berlaku. Linux tidak memiliki fasilitas untuk melakukan ini. Deskriptor file Linux (POSIX) tidak selalu merujuk ke file, dan bahkan jika mereka merujuk ke inode, bukan nama file. Deskriptor dapat menunjuk ke file yang dihapus (yang karenanya tidak memiliki nama, ini adalah cara umum untuk membuat file temp) atau mungkin menunjuk ke inode dengan banyak nama (tautan keras).
Tyler McHenry

3
Coba lihat kode sumber lsof. :) Itulah yang saya lakukan ketika saya memiliki pertanyaan yang sama beberapa waktu yang lalu. Jika bekerja pada ilmu hitam dan kambing kurban - Anda tidak dapat berharap untuk meniru perilakunya. Untuk lebih spesifik, lsof digabungkan erat dengan kernel linux, dan tidak melakukan apa yang dilakukannya melalui API apa pun yang tersedia untuk kode lahan pengguna.
Tyler McHenry

27
Linux memiliki API proc non-portabel untuk ini. Memang ada batasan, tetapi mengatakan itu tidak mungkin hanyalah salah.
bdonlan

1
@Tyler - lsof berjalan di userspace. Oleh karena itu, ada API untuk apa pun yang dilakukannya tersedia untuk kode userland :)
bdonlan

1
@Duck, portabilitasnya mungkin ada mengapa sumber lsof memiliki begitu banyak ilmu hitam; setiap varian UNIX melakukannya secara berbeda. Antarmuka proc linux tidak terlalu buruk, sungguh, meskipun agak jarang didokumentasikan.
bdonlan
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.