2010-01-08 13 views
66

क्या लिनक्स पर एक खुली फ़ाइल हैंडलर के लिए होता है, तो उठाई फ़ाइल इस बीच हो जाता है:अगर उठाई फ़ाइल में ले जाया जाता है क्या लिनक्स पर एक खुली फ़ाइल हैंडलर का क्या होता है, हटाने

  • दूर ले जाया गया -> फ़ाइल हैंडलर है वैध रहता है?
  • हटाया गया -> क्या यह एक ईबीएडीएफ की ओर जाता है, जो एक अवैध फ़ाइल हैंडलर का संकेत देता है?
  • एक नई फ़ाइल द्वारा प्रतिस्थापित -> क्या फ़ाइल हैंडलर इस नई फ़ाइल को इंगित करता है?
  • एक नई फ़ाइल के लिए एक कठिन लिंक द्वारा बदलें -> क्या मेरा फ़ाइल हैंडलर इस लिंक का पालन करता है?
  • एक नई फ़ाइल के मुलायम लिंक द्वारा प्रतिस्थापित करें -> क्या मेरे फ़ाइल हैंडलर ने अब इस सॉफ्ट लिंक फ़ाइल को मारा है?

मैं ऐसे प्रश्न क्यों पूछ रहा हूं: मैं हॉट-प्लग हार्डवेयर (जैसे यूएसबी डिवाइस इत्यादि) का उपयोग कर रहा हूं। ऐसा हो सकता है कि डिवाइस (और यह भी/dev/file) उपयोगकर्ता या किसी अन्य Gremlin द्वारा पुनः प्राप्त किया जाता है।

इससे निपटने का सबसे अच्छा अभ्यास क्या है?

उत्तर

96

फ़ाइल ले जाया जाता है (एक ही फाइल सिस्टम में) या नाम बदला है, तो फ़ाइल हैंडल खुला रहता है और अभी भी पढ़ सकते हैं और फ़ाइल में लिखने के लिए इस्तेमाल किया जा सकता है।

यदि फ़ाइल हटा दी गई है, तो फ़ाइल हैंडल खुला रहता है और अभी भी इसका उपयोग किया जा सकता है (यह कुछ लोगों की अपेक्षा नहीं है)। अंतिम संभाल बंद होने तक फ़ाइल वास्तव में हटाई नहीं जाएगी।

यदि फ़ाइल को एक नई फ़ाइल द्वारा प्रतिस्थापित किया गया है, तो यह बिल्कुल निर्भर करता है कि कैसे। अगर फ़ाइल की सामग्री ओवरराइट की जाती है, तो फ़ाइल हैंडल अभी भी मान्य होगा और नई सामग्री तक पहुंच जाएगी। यदि मौजूदा फ़ाइल अनलिंक है और एक ही नाम के साथ बनाया गया नया है, या rename() का उपयोग कर मौजूदा फ़ाइल पर एक नई फ़ाइल ले जाया गया है, तो यह हटाए जाने जैसा ही है (ऊपर देखें) - यानी, फ़ाइल हैंडल संदर्भ जारी रहेगा फ़ाइल के मूल संस्करण के लिए।

सामान्य रूप से, फ़ाइल खोलने के बाद, फ़ाइल खुलती है, और कोई भी निर्देशिका संरचना बदलने वाला कोई भी इसे बदल सकता है - वे स्थानांतरित कर सकते हैं, फ़ाइल का नाम बदल सकते हैं, या इसके स्थान पर कुछ और डाल सकते हैं, यह बस खुला रहता है।

यूनिक्स में कोई डिलीट नहीं है, केवल unlink(), जो समझ में आता है क्योंकि यह फ़ाइल को जरूरी नहीं हटाता है - बस निर्देशिका से लिंक हटा देता है।


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

+0

मुझे लगता है कि फ़ाइल की एक निर्देशिका निर्देशिका हटा दी गई है तो आपका दूसरा बिंदु समान रूप से लागू होता है। ऐसा क्या? –

+1

मुझे एक चीज़ में रूचि है: यदि आप फ़ाइल को ओवरराइट करने के लिए सीपी कमांड का उपयोग करते हैं, तो क्या यह पहला मामला है या दूसरा मामला है? – xuhdev

1

हटाए गए फ़ाइल की इन-मेमोरी जानकारी (आपके द्वारा दिए गए सभी उदाहरण हटाए गए फ़ाइल के उदाहरण हैं) साथ ही साथ ऑन-डिस्क ऑन-डिस्क अस्तित्व में रहती है जब तक कि फ़ाइल बंद न हो जाए।

हार्डवेयर हॉटप्लग किया जा रहा है एक पूरी तरह से अलग मुद्दा है, और आपको अपने प्रोग्राम को लंबे समय तक जीवित रहने की उम्मीद नहीं करनी चाहिए यदि ऑन-डिस्क इनोड्स या मेटाडाटा पर बदल गया है।

5

फ़ाइल हैंडल एक इनोड को पथ पर नहीं इंगित करता है, इसलिए आपके अधिकांश परिदृश्य अभी भी काम करते हैं जैसा कि आप मानते हैं, क्योंकि हैंडल अभी भी फ़ाइल को इंगित करता है।

विशेष रूप से, हटाए गए परिदृश्य के साथ - फ़ंक्शन को किसी कारण के लिए "अनलिंक" कहा जाता है, यह फ़ाइल नाम (एक दंत चिकित्सा) और फ़ाइल के बीच "लिंक" को नष्ट कर देता है। जब आप कोई फ़ाइल खोलते हैं, तो इसे अनलिंक करें, फ़ाइल वास्तव में तब तक मौजूद है जब तक कि इसकी संदर्भ संख्या शून्य पर न हो, जो तब होता है जब आप हैंडल बंद करते हैं।

संपादित करें: हार्डवेयर के मामले में, यदि आप किसी विशिष्ट डिवाइस नोड के लिए एक संभाल खोला है आप उपकरण को अनप्लग अगर, कर्नेल सब असफल हो जायेगी यह करने तक पहुँचता है, भले ही डिवाइस वापस आता है। आपको डिवाइस को बंद करना होगा और इसे फिर से खोलना होगा।

2

मुझे अन्य परिचालनों के बारे में निश्चित नहीं है, लेकिन हटाए जाने के लिए: फ़ाइल को अंतिम खुले हैंडल तक बंद होने तक विलोपन आसानी से नहीं होता है (भौतिक रूप से, यानी फाइल सिस्टम में)। इस प्रकार आपके आवेदन के तहत से फ़ाइल को हटाना संभव नहीं होना चाहिए।

कुछ ऐप्स (जो दिमाग में नहीं आते हैं) इस व्यवहार पर भरोसा करते हैं, फाइलें बनाने, खोलने और तुरंत हटाने के द्वारा, जो तब तक आवेदन के रूप में बिल्कुल सही रहते हैं - अन्य अनुप्रयोगों को पहले ऐप के बारे में पता होना चाहिए प्रक्रिया नक्शे और इस तरह की देखने के बिना जीवन चक्र।

यह संभव है कि अन्य सामानों पर भी समान विचार लागू हों।

1

अंडर/proc/निर्देशिका के तहत आपको वर्तमान में सक्रिय प्रत्येक प्रक्रिया की एक सूची मिल जाएगी, बस अपने पीआईडी ​​को ढूंढें और संबंधित सभी डेटा वहां हैं। एक इंटरस्टेस्टिंग जानकारी फ़ोल्डर fd/है, आपको वर्तमान में प्रक्रिया द्वारा खोले गए सभी फ़ाइल हैंडलर मिलेंगे।

आखिरकार आपको अपने डिवाइस (नीचे/dev/या यहां तक ​​कि/proc/bus/usb /) के लिए एक प्रतीकात्मक लिंक मिलेगा, यदि डिवाइस लटकता है तो लिंक मर जाएगा और इस हैंडल को रीफ्रेश करना असंभव होगा, प्रक्रिया को बंद करने और इसे फिर से खोलने (यहां तक ​​कि पुनर्संयोजन के साथ)

इस कोड को चाहिए इस अंतिम कोड सरल है अपने पीआईडी ​​का लिंक वर्तमान स्थिति

#include <unistd.h> 
#include <stdio.h> 
#include <dirent.h> 

int main() { 
    // the directory we are going to open 
    DIR   *d; 

    // max length of strings 
    int maxpathlength=256; 

    // the buffer for the full path 
    char path[maxpathlength]; 

    // /proc/PID/fs contains the list of the open file descriptors among the respective filenames 
    sprintf(path,"/proc/%i/fd/",getpid()); 

    printf("List of %s:\n",path); 

    struct dirent *dir; 
    d = opendir(path); 
    if (d) { 
     //loop for each file inside d 
     while ((dir = readdir(d)) != NULL) { 

      //let's check if it is a symbolic link 
      if (dir->d_type == DT_LNK) { 

       const int maxlength = 256; 

       //string returned by readlink() 
       char hardfile[maxlength]; 

       //string length returned by readlink() 
       int len; 

       //tempath will contain the current filename among the fullpath 
       char tempath[maxlength]; 

       sprintf(tempath,"%s%s",path,dir->d_name); 
       if ((len=readlink(tempath,hardfile,maxlength-1))!=-1) { 
        hardfile[len]='\0'; 
         printf("%s -> %s\n", dir->d_name,hardfile); 

       } else 
        printf("error when executing readlink() on %s\n",tempath); 

      } 
     } 

     closedir(d); 
    } 
    return 0; 
} 

पढ़ सकते हैं, आप linkat समारोह के साथ खेल सकते हैं।

int 
open_dir(char * path) 
{ 
    int fd; 

    path = strdup(path); 
    *strrchr(path, '/') = '\0'; 
    fd = open(path, O_RDONLY | O_DIRECTORY); 
    free(path); 

    return fd; 
} 

int 
main(int argc, char * argv[]) 
{ 
    int odir, ndir; 
    char * ofile, * nfile; 
    int status; 

    if (argc != 3) 
    return 1; 

    odir = open_dir(argv[1]); 
    ofile = strrchr(argv[1], '/') + 1; 

    ndir = open_dir(argv[2]); 
    nfile = strrchr(argv[2], '/') + 1; 

    status = linkat(odir, ofile, ndir, nfile, AT_SYMLINK_FOLLOW); 
if (status) { 
    perror("linkat failed"); 
} 


    return 0; 
} 
2

यदि आप यह जांचना चाहते हैं कि फ़ाइल हैंडलर (फ़ाइल डिस्क्रिप्टर) ठीक है, तो आप इस फ़ंक्शन को कॉल कर सकते हैं।

/** 
* version : 1.1 
* date : 2015-02-05 
* func : check if the fileDescriptor is fine. 
*/ 

#include <unistd.h> 
#include <fcntl.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <stdio.h> 

/** 
* On success, zero is returned. On error, -1 is returned, and errno is set 
*  appropriately. 
*/ 
int check_fd_fine(int fd) { 
    struct stat _stat; 
    int ret = -1; 
    if(!fcntl(fd, F_GETFL)) { 
     if(!fstat(fd, &_stat)) { 
      if(_stat.st_nlink >= 1) 
       ret = 0; 
      else 
       printf("File was deleted!\n"); 
     } 
    } 
    if(errno != 0) 
     perror("check_fd_fine"); 
    return ret; 
} 

int main() { 
    int fd = -1; 
    fd = open("/dev/ttyUSB1", O_RDONLY); 
    if(fd < 0) { 
     perror("open file fail"); 
     return -1; 
    } 
    // close or remove file(remove usb device) 
// close(fd); 
    sleep(5); 
    if(!check_fd_fine(fd)) { 
     printf("fd okay!\n"); 
    } else { 
     printf("fd bad!\n"); 
    } 
    close(fd); 
    return 0; 
} 
+0

'if (! Fcntl (fd, F_GETFL)) का बिंदु क्या है {' चेक? मुझे लगता है कि आप वहां 'ईबीएडीएफ' की तलाश में हैं। (आप शायद 'errno' से 0 को प्रारंभ करना भूल गए हैं)। – woky