C में फ़ाइल डिस्क्रिप्टर से फ़ाइल नाम पुनः प्राप्त करें


105

क्या सी में फ़ाइल डिस्क्रिप्टर (लिनक्स) का फ़ाइल नाम प्राप्त करना संभव है?


मुझे लगता है, चुना हुआ जवाब ज़्नक को दिया जाना चाहिए क्योंकि उसके समाधान में बेहतर पोर्टेबिलिटी है और इसमें कोई ध्यान नहीं दिया गया है।
सर्गेई

यह Ubuntu 14.04 (कर्नेल 3.16.0-76-जेनेरिक) पर समर्थित नहीं है। मुझे लगता है कि यह लिनक्स पर बिल्कुल भी समर्थित नहीं है।
felipou

MacOS के लिए, D.Nathanel द्वारा एक अन्य प्रश्न का उत्तर देखें ।
जोनाथन लेफ्लर 16

जवाबों:


120

आप उपयोग कर सकते हैं readlinkपर /proc/self/fd/NNNजहां NNN फ़ाइल जानकारी देता है। यह आपको फ़ाइल का नाम देगा जैसा कि इसे खोला गया था - हालांकि, यदि फ़ाइल को तब से स्थानांतरित या हटा दिया गया था, तो यह अब सटीक नहीं हो सकता है (हालांकि लिनक्स कुछ मामलों में नाम बदल सकता है)। सत्यापित करने के लिए, आपके द्वारा statदिया गया फ़ाइल नाम और fstatfd, और सुनिश्चित करें st_devऔर st_inoसमान हैं।

बेशक, सभी फाइल डिस्क्रिप्टर फाइलों को संदर्भित नहीं करते हैं, और उन लोगों के लिए जिन्हें आप कुछ अजीब पाठ स्ट्रिंग देखेंगे, जैसे कि pipe:[1538488]। चूंकि सभी वास्तविक फ़ाइलनाम पूर्ण पथ होंगे, आप यह निर्धारित कर सकते हैं कि ये आसानी से पर्याप्त हैं। इसके अलावा, जैसा कि अन्य ने नोट किया है, फाइलों में कई हार्डलिंक हैं जो उन्हें इंगित कर सकते हैं - यह केवल उसी के बारे में रिपोर्ट करेगा जिसे इसके साथ खोला गया था। यदि आप किसी दिए गए फ़ाइल के लिए सभी नाम ढूंढना चाहते हैं, तो आपको बस संपूर्ण फाइल सिस्टम को पार करना होगा।


9
जब तक मूल फ़ाइल में अभी भी इसके संदर्भ हैं (एक खुला fdऐसा संदर्भ होगा), इनोड संख्या का पुन: उपयोग नहीं किया जा सकता है। फ़ाइल बंद करने के बाद या इसे खोलने से पहले इनोड नंबर का उपयोग करने वाला कोई भी सॉफ्टवेयर स्वाभाविक रूप से दौड़ की स्थिति के अधीन है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

3
खतरे, रॉबिन्सन! यह हमेशा काम नहीं करता है --- यदि आप setuid()ट्रिक्स करते हैं , तो /proc/self/fdआपकी प्रक्रिया द्वारा सुलभ नहीं होना संभव है। देखें: permalink.gmane.org/gmane.linux.kernel/1302546
डेविड

2
@bdonlan: और मामले में / खरीद आरोहित नहीं है?
user2284570

1
@ user2284570, यह उत्तर लिनक्स-विशिष्ट है। मुझे नहीं पता कि NetBSD सभी पर procfs का समर्थन करता है - यदि आपका साझा होस्ट इसे प्रदान नहीं करता है, तो यह शायद इसलिए है क्योंकि NetBSD इसे बिल्कुल भी समर्थन नहीं करता है और इसके बजाय किसी अन्य तंत्र का उपयोग करता है। आप NetBSD फ़ोकस के साथ एक और सवाल पोस्ट करना चाह सकते हैं, अगर कोई जानता है कि NetBSD इस जानकारी को कैसे उजागर करता है (आप नीचे zneak के उत्तर को भी आज़माना चाह सकते हैं, OS X, Linux से BSD के समान है)
bdonlan

1
@bdonlan: NetBSD समर्थन / खरीद लेकिन इसे माउंट करना अनिवार्य नहीं है। जितनी बार मैंने उल्लेख किया, उत्तर "उच्च लागत प्रदाता से दूर हो गया और आपको मिल जाएगा / खरीदूंगा"। तो मैं एक समाधान की तलाश में हूँ।
user2284570

90

मुझे मैक ओएस एक्स पर यह समस्या थी। हमारे पास /procवर्चुअल फ़ाइल सिस्टम नहीं है, इसलिए स्वीकृत समाधान काम नहीं कर सकता है।

हम, इसके बजाय, के लिए एक F_GETPATHआदेश है fcntl:

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

तो फाइल डिस्क्रिप्टर से जुड़ी फाइल पाने के लिए, आप इस स्निपेट का उपयोग कर सकते हैं:

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

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

चूंकि मुझे कभी याद नहीं है कि कहां MAXPATHLENपरिभाषित किया गया है, मैंने सोचा कि PATH_MAXसिस्लीमिट्स से ठीक हो जाएगा।


@ यूचुगाका, शायद नहीं। उपयोगgetsockname
18

2
आप क्या उम्मीद करते हैं? जब तक यह एक यूनिक्स सॉकेट नहीं है, तब तक इसमें कोई फाइल नहीं जुड़ी है।
zneak

2
@uchuugaka हां, सब कुछ एक फाइल है, लेकिन सब कुछ नहीं है एक डायरेक्टरी प्रविष्टि है जिसमें नाम और फाइलसिस्टम ट्री के अंदर एक स्थान है। एक फ़ाइल को एक इनोड द्वारा दर्शाया गया है, यह किसी भी निर्देशिका प्रविष्टि को संदर्भित किए बिना मौजूद हो सकता है।
lgeorget

9
<Sys / param.h> में: #define MAXPATHLEN PATH_MAX
जेवर

1
मैंने अभी इसका परीक्षण किया है और यह सही रहता है यदि फ़ाइल ले जाया जाता है और आप इसे फिर से कॉल करते हैं (मतलब: आपको फ़ाइल का नया पथ मिलता है)। हालाँकि यह लिनक्स पर समर्थित नहीं है (उबंटू 14.04 पर परीक्षण किया गया - F_GETPATH ​​परिभाषित नहीं है)।
felipou


15

जैसा कि टायलर बताते हैं, ऐसा करने का कोई तरीका नहीं है जिसे आपको "सीधे और मज़बूती से" की आवश्यकता है, क्योंकि किसी दिए गए एफडी में 0 फ़ाइल नाम (विभिन्न मामलों में) या> 1 (कई "हार्ड लिंक" के अनुरूप हो सकते हैं कि बाद की स्थिति आम तौर पर कैसे वर्णित है। )। यदि आपको अभी भी सभी सीमाओं के साथ कार्यक्षमता की आवश्यकता है (गति पर और 0, 2, ... 1 के बजाय परिणाम प्राप्त करने की संभावना पर), तो यहां बताया गया है कि आप यह कैसे कर सकते हैं: पहला, एफडीएस एफडी - यह आपको बताता है परिणाम मेंstruct stat , फ़ाइल किस डिवाइस पर रहती है, उसके पास कितने हार्ड लिंक हैं, क्या यह एक विशेष फ़ाइल है, आदि। यह पहले से ही आपके प्रश्न का उत्तर दे सकता है - उदाहरण के लिए यदि 0 हार्ड लिंक आप जानते हैं कि वास्तव में कोई संगत फ़ाइल नाम नहीं है डिस्क पर।

यदि आंकड़े आपको आशा देते हैं, तो आपको प्रासंगिक डिवाइस पर निर्देशिकाओं के "पेड़ को चलना" पड़ता है जब तक कि आपको सभी हार्ड लिंक नहीं मिलते (या बस पहले एक, यदि आपको एक से अधिक की आवश्यकता नहीं है और कोई भी करेगा )। उस उद्देश्य के लिए, आप का उपयोग readdir (और opendir और निश्चित रूप से ग) रिकर्सिवली उपनिर्देशिका खोलने जब तक आप एक में मिल struct direntइस प्रकार प्राप्त एक ही आइनोड संख्या आप मूल में थाstruct stat (उस समय आपके पास पूरे रास्ते चाहते हैं, बल्कि सिर्फ नाम से, आपको इसे फिर से बनाने के लिए निर्देशिकाओं की श्रृंखला को पीछे की ओर चलना होगा)।

यदि यह सामान्य दृष्टिकोण स्वीकार्य है, लेकिन आपको अधिक विस्तृत सी कोड की आवश्यकता है, तो हमें बताएं, यह लिखना कठिन नहीं होगा (हालांकि मैं इसे बेकार नहीं होने पर नहीं लिखूंगा, अर्थात आप अनिवार्य रूप से धीमा प्रदर्शन या सामना नहीं कर सकते हैं अपने आवेदन के प्रयोजनों के लिए होने की संभावना! = 1 परिणाम ;-)।


9

यह असंभव के रूप में लिखने से पहले मैं आपको lsof कमांड के स्रोत कोड को देखने का सुझाव देता हूं ।

प्रतिबंध हो सकते हैं लेकिन फ़ाइल डिस्क्रिप्टर और फ़ाइल नाम का निर्धारण करने में lsof सक्षम लगता है। यह जानकारी / proc फाइल सिस्टम में मौजूद है, इसलिए इसे आपके प्रोग्राम से प्राप्त करना संभव है।


6

आप स्टैटिक स्टेटमेंट द्वारा फाइल के इनकोड को प्राप्त करने के लिए fstat () का उपयोग कर सकते हैं। फिर, रीडडायर () का उपयोग करके आप उन लोगों के साथ मिले इनोड की तुलना कर सकते हैं जो एक निर्देशिका में मौजूद हैं (स्ट्रक्चर डाइरेंट) (यह मानते हुए कि आप डायरेक्टरी को जानते हैं, अन्यथा आपको पूरा फाइल सिस्टम खोजना होगा) और संबंधित फाइल का नाम ढूंढना होगा। बुरा?


2

असंभव। फ़ाइल डिस्क्रिप्टर में फ़ाइल सिस्टम में कई नाम हो सकते हैं, या इसमें कोई नाम नहीं हो सकता है।

संपादित करें: मान लें कि आप एक सादे पुराने POSIX सिस्टम के बारे में बात कर रहे हैं, बिना किसी OS- विशिष्ट API के, क्योंकि आपने OS निर्दिष्ट नहीं किया था।


4
तब मेरा उत्तर लागू होता है। लिनक्स में ऐसा करने के लिए कोई सुविधा नहीं है। लिनक्स (POSIX) फ़ाइल डिस्क्रिप्टर आवश्यक रूप से फ़ाइलों को संदर्भित नहीं करते हैं, और भले ही वे ऐसा करते हैं कि वे इनोड्स को संदर्भित करते हैं, फ़ाइल नाम नहीं। एक डिस्क्रिप्टर एक हटाई गई फ़ाइल को इंगित कर सकता है (जिसका कोई नाम नहीं है, यह अस्थायी फ़ाइलों को बनाने का एक सामान्य तरीका है) या यह कई नामों (हार्ड लिंक) के साथ एक इनोड को इंगित कर सकता है।
टायलर मैकहेनरी

3
Lsof source कोड पर एक नज़र डालने की कोशिश करें। :) यह वही है जो मैंने तब किया था जब मेरे पास कुछ समय पहले यही सवाल था। lsof काला जादू और बलि के बकरे पर काम करता है - आप इसके व्यवहार की नकल करने की उम्मीद नहीं कर सकते। अधिक विशिष्ट होने के लिए, lsof को कसकर लिनक्स कर्नेल के साथ जोड़ा जाता है, और यह ऐसा नहीं करता है जो किसी भी एपीआई के माध्यम से करता है जो उपयोगकर्ता-भूमि कोड के लिए उपलब्ध है।
टायलर मैकहेनरी

27
लिनक्स में इसके लिए एक गैर-पोर्टेबल खरीद एपीआई है। वहाँ वास्तव में सीमाएँ हैं, लेकिन यह असंभव है कह रही है कि सिर्फ सादा झूठ है।
बोल्डन

1
@ टायलर - lsof यूजरस्पेस में चलता है। इसलिए,
यूजरलैंड

1
@Duck, पोर्टेबिलिटी शायद यही कारण है कि lsof के स्रोत में इतना काला जादू है; प्रत्येक UNIX संस्करण इसे अलग तरीके से करता है। Linux proc interfaces बहुत ख़राब नहीं है, वास्तव में, alebit बल्कि काफी डॉक्यूमेंटेड है।
बेन्डलान जुएल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.