Dosya adını C'deki dosya tanımlayıcısından alın


105

C'de bir dosya tanımlayıcısının (Linux) dosya adını almak mümkün müdür?


Sanırım, çözümü daha iyi taşınabilirliğe sahip olduğu ve herhangi bir erişim sorunu olmadığı için seçilen yanıt zneak'a verilmelidir.
Sergei

Ubuntu 14.04'te desteklenmez (kernel 3.16.0-76-generic). Sanırım Linux'ta hiç desteklenmiyor.
felipou

MacOS için D. Natanael'in başka bir sorusuna verilen bu yanıta bakın .
Jonathan Leffler

Yanıtlar:


120

Sen kullanabilirsiniz readlinküzerinde /proc/self/fd/NNNNNN dosya tanıtıcısı olduğu. Bu size dosyanın adını, açıldığı zamandaki haliyle verecektir - ancak, o zamandan beri dosya taşınmış veya silinmişse, artık doğru olmayabilir (Linux bazı durumlarda yeniden adları izleyebilmesine rağmen). Doğrulamak için, statverilen dosya adı ve fstatsahip olduğunuz fd st_devve st_inoaynı olduğundan emin olun .

Elbette, tüm dosya tanımlayıcıları dosyalara atıfta bulunmaz ve bunlar için pipe:[1538488]. Gerçek dosya adlarının tümü mutlak yollar olacağından, hangilerinin yeterli olduğunu kolayca belirleyebilirsiniz. Ayrıca, diğerlerinin de belirttiği gibi, dosyalar kendilerine işaret eden birden çok sabit bağlantıya sahip olabilir - bu, yalnızca açıldığı dosyayı bildirir. Belirli bir dosya için tüm isimleri bulmak istiyorsanız, sadece tüm dosya sistemini dolaşmanız gerekir.


9
Sürece orijinal dosya hala başvurular olduğu gibi (açık fdböyle bir referans olacaktır), inode numarası olamaz yeniden. Dosyayı kapattıktan sonra veya açmadan önce bir inode numarasını kullanan herhangi bir yazılım, doğası gereği yarış koşullarına tabidir.
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

3
Tehlike, Will Robinson! Bu her zaman işe yaramaz - setuid()hile yaparsanız /proc/self/fd, işleminiz tarafından erişilebilir olmamak mümkündür . Bkz: permalink.gmane.org/gmane.linux.kernel/1302546
David,

2
@bdonlan: ve durumda / proc bağlanmamış mı?
user2284570

1
@ user2284570, bu yanıt Linux'a özgüdür. NetBSD'nin procfs'yi destekleyip desteklemediğini bilmiyorum - eğer paylaşılan ana bilgisayarınız bunu sağlamıyorsa, bunun nedeni muhtemelen NetBSD'nin onu hiç desteklememesi ve bunun yerine başka bir mekanizma kullanmasıdır. NetBSD'nin bu bilgiyi nasıl açığa çıkardığını bilip bilmediğini görmek için NetBSD odaklı başka bir soru göndermek isteyebilirsiniz (aşağıdaki zneak'ın cevabını da deneyebilirsiniz, OS X Linux'tan
BSD'ye

1
@bdonlan: NetBSD desteği / proc, ancak takılması zorunlu değildir. Bahsettiğim her defasında, cevap "daha yüksek bir maliyet sağlayıcıya geçiş yapın ve / proc alacaksınız" oldu. Bu yüzden procless bir çözüm arıyorum.
user2284570

90

Mac OS X'te bu sorunu yaşadım. /procSanal dosya sistemimiz yok, bu yüzden kabul edilen çözüm çalışamıyor.

Bunun yerine aşağıdakiler için bir F_GETPATHemrimiz var fcntl:

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

Dolayısıyla, bir dosya tanımlayıcısıyla ilişkili dosyayı almak için şu pasajı kullanabilirsiniz:

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

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

Nerenin MAXPATHLENtanımlandığını hiç hatırlamadığım PATH_MAXiçin sistem sınırlarından iyi olacağını düşündüm .


@uchuugaka, muhtemelen değil. Kullanın getsockname.
zneak

2
Ne bekliyorsunuz? Bir UNIX soketi olmadığı sürece, ilişkilendirilmiş bir dosyası yoktur.
zneak

2
@uchuugaka Evet, her şey bir dosyadır, ancak her şey dosya sistemi ağacının içinde adı ve konumu olan bir dizin girişi değildir . Bir dosya bir inode ile temsil edilir, kendisine atıfta bulunan herhangi bir dizin girişi olmadan var olabilir.
lgeorget

9
<Sys / param.h> içinde: #define MAXPATHLEN PATH_MAX
geowar

1
Bunu daha yeni test ettim ve dosya taşınırsa ve siz onu tekrar çağırırsanız doğru kalır (yani: dosyanın yeni yolunu alırsınız). Ancak bu, linux üzerinde desteklenmemektedir (Ubuntu 14.04 üzerinde test edilmiştir - F_GETPATH ​​tanımlanmamıştır).
felipou


15

Tyler'ın işaret ettiği gibi, istediğiniz şeyi "doğrudan ve güvenilir bir şekilde" yapmanın bir yolu yoktur, çünkü belirli bir FD 0 dosya adına (çeşitli durumlarda) veya> 1'e (birden çok "sabit bağlantı") karşılık gelebilir, son durum genel olarak açıklanır ). Hala tüm sınırlamalarla işlevselliğe ihtiyacınız varsa (hızda VE 1 yerine 0, 2, ... sonuç alma olasılığında), bunu şu şekilde yapabilirsiniz: önce, FD'yi - bu size söyler , sonuçta struct stat, dosyanın hangi cihazda yaşadığını, kaç tane sabit bağlantıya sahip olduğunu, özel bir dosya olup olmadığını, vb. Bu, sorunuzu zaten yanıtlayabilir - örneğin, 0 sabit bağlantı varsa, gerçekte karşılık gelen bir dosya adı olmadığını BİLECEĞİNİZ diskte.

İstatistikler size umut veriyorsa, tüm sabit bağlantıları bulana kadar (veya birden fazlasına ihtiyacınız yoksa yalnızca ilkini bulana kadar) ilgili cihazdaki dizinlerin "ağacında yürümeniz" gerekir. ). Bu amaçla, readdir (ve tabii ki opendir & c) alt dizinleri tekrar tekrar açarak struct dirent, orijinalde sahip olduğunuz aynı inode numarasını bulana kadar kullanırsınız struct stat(bu durumda, sadece ad yerine tüm yolu istiyorsanız, dizinler zincirini yeniden yapılandırmak için geriye doğru yürümeniz gerekir).

Bu genel yaklaşım kabul edilebilirse, ancak daha ayrıntılı C koduna ihtiyacınız varsa, bize bildirin, yazmak zor olmayacaktır (ancak işe yaramazsa yazmamayı tercih ederim, yani kaçınılmaz olarak yavaş performansa veya Başvurunuzun amaçları doğrultusunda! = 1 sonuç alma imkanı ;-).


9

Bunu imkansız diye yazmadan önce, lsof komutunun kaynak koduna bakmanızı öneririm .

Kısıtlamalar olabilir, ancak lsof, dosya tanımlayıcısını ve dosya adını belirleyebilir. Bu bilgiler / proc dosya sisteminde bulunur, bu yüzden programınızdan ulaşmanız mümkün olmalıdır.


6

Struct stat ile dosyanın inode'unu almak için fstat () kullanabilirsiniz. Daha sonra readdir () kullanarak bulduğunuz inode'u bir dizinde bulunanlarla (struct dirent) karşılaştırabilirsiniz (dizini bildiğinizi varsayarak, aksi takdirde tüm dosya sistemini aramanız gerekir) ve ilgili dosya adını bulabilirsiniz. Kötü mü?


2

İmkansız. Bir dosya tanımlayıcısının dosya sisteminde birden fazla adı olabilir veya hiç adı olmayabilir.

Düzenleme: Bir işletim sistemi belirtmediğiniz için işletim sistemine özgü herhangi bir API olmadan düz eski bir POSIX sisteminden bahsettiğinizi varsayalım.


4
o zaman cevabım geçerlidir. Linux'un bunu yapacak tesisi yoktur. Linux (POSIX) dosya tanımlayıcıları dosyalara atıfta bulunmazlar ve yapsalar bile dosya adlarına değil, düğümlere atıfta bulunurlar. Bir tanımlayıcı, silinmiş bir dosyaya işaret edebilir (bu nedenle adı yoktur, bu, geçici dosyalar oluşturmanın yaygın bir yoludur) veya birden çok ada (sabit bağlantılar) sahip bir inode'a işaret edebilir.
Tyler McHenry

3
Lsof kaynak koduna bir göz atmayı deneyin. :) Bir süre önce ben de aynı soruyu sorduğumda yaptığım buydu. lsof, kara büyü ve kurbanlık keçiler üzerinde çalışıyor - onun davranışını kopyalamayı umut edemezsiniz. Daha spesifik olmak gerekirse, lsof, linux çekirdeği ile sıkı sıkıya bağlıdır ve kullanıcı-arazi kodu için mevcut olan herhangi bir API aracılığıyla yaptığı şeyi yapmaz.
Tyler McHenry

27
Linux bunun için taşınabilir olmayan bir proc API'ye sahiptir. Gerçekten de sınırlamalar var, ancak bunun imkansız olduğunu söylemek tamamen yanlış.
bdonlan

1
@Tyler - lsof kullanıcı alanında çalışır. Bu nedenle, kullanıcı alanı kodu için mevcut olan her şey için bir API vardır :)
bdonlan

1
@Duck, oradaki taşınabilirlik muhtemelen lsof'un kaynağında bu kadar çok kara büyü var; her UNIX varyantı bunu farklı şekilde yapar. Linux proc arayüzleri çok da kötü değil, gerçekten, seyrek olarak belgelenmesine rağmen.
bdonlan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.