যদি পয়েন্টযুক্ত ফাইলটি সরানো বা মুছে ফেলা হয় তবে লিনাক্সে একটি ওপেন ফাইল হ্যান্ডেলটি ঘটবে


107

যদি পয়েন্টযুক্ত ফাইলটি ইতিমধ্যে পায় তবে লিনাক্সে একটি ওপেন ফাইল হ্যান্ডেল কি হবে:

  • সরানো -> ফাইল হ্যান্ডেল কি বৈধ থাকে?
  • মোছা -> এটি কি কোনও EBADF বাড়ে যা একটি অবৈধ ফাইল হ্যান্ডেল নির্দেশ করে?
  • একটি নতুন ফাইল দ্বারা প্রতিস্থাপন -> ফাইল হ্যান্ডেল কি এই নতুন ফাইলটির দিকে নির্দেশ করছে?
  • একটি নতুন ফাইলের একটি হার্ড লিঙ্ক দ্বারা প্রতিস্থাপন -> আমার ফাইল হ্যান্ডেল কি এই লিঙ্কটিকে "অনুসরণ" করে?
  • একটি নতুন ফাইলের নরম লিঙ্ক দ্বারা প্রতিস্থাপন করা হয়েছে -> আমার ফাইল হ্যান্ডেল কি এই নরম লিঙ্ক ফাইলটি এখন আঘাত করে?

আমি কেন এই জাতীয় প্রশ্ন করছি: আমি হট-প্লাগযুক্ত হার্ডওয়্যার (যেমন ইউএসবি ডিভাইস ইত্যাদি) ব্যবহার করছি। এটি ঘটতে পারে, ডিভাইসটি (এবং তার / dev / ফাইল) ব্যবহারকারী বা অন্য একটি গ্রিমলিনের সাথে পুনরায় সংযুক্ত হতে পারে।

এর সাথে ডিল করার সেরা অনুশীলনটি কী?

উত্তর:


159

যদি ফাইলটি সরানো হয় (একই ফাইল সিস্টেমে) বা পুনরায় নামকরণ করা হয়, তবে ফাইল হ্যান্ডেলটি উন্মুক্ত থাকে এবং এখনও ফাইলটি পড়তে এবং লিখতে ব্যবহৃত হতে পারে।

যদি ফাইলটি মুছে ফেলা হয় তবে ফাইল হ্যান্ডেলটি উন্মুক্ত থাকে এবং এখনও ব্যবহার করা যেতে পারে (এটি কিছু লোক প্রত্যাশা করে না)। শেষ হ্যান্ডেলটি বন্ধ না হওয়া পর্যন্ত ফাইলটি সত্যই মুছে ফেলা হবে না।

যদি ফাইলটি কোনও নতুন ফাইল দ্বারা প্রতিস্থাপন করা হয় তবে এটি ঠিক কীভাবে তা নির্ভর করে। যদি ফাইলটির বিষয়বস্তু ওভাররাইট করা হয় তবে ফাইল হ্যান্ডেলটি এখনও বৈধ থাকবে এবং নতুন সামগ্রীটি অ্যাক্সেস করবে। যদি বিদ্যমান ফাইলটি লিঙ্কযুক্ত থাকে এবং একই নামের সাথে একটি নতুন ফাইল তৈরি হয় বা যদি একটি নতুন ফাইল ব্যবহার করে বিদ্যমান ফাইলটিতে সরানো হয় তবে rename()এটি মুছে ফেলার মতোই (উপরে দেখুন) - যা ফাইল হ্যান্ডেলটি উল্লেখ করতে থাকবে মূল ফাইলের সংস্করণ।

সাধারণভাবে, একবার ফাইলটি ওপেন হয়ে গেলে, ফাইলটি ওপেন হয় এবং ডিরেক্টরি কাঠামো পরিবর্তন করে এমন কেউ পরিবর্তন করতে পারে না - তারা স্থানান্তর করতে, ফাইলটির নাম পরিবর্তন করতে বা তার জায়গায় অন্য কোনও কিছু রাখতে পারে, এটি কেবল খোলা থাকে।

ইউনিক্সে কোনও মুছে ফেলা হয় না, কেবল unlink()এটিই বোঝায় যে এটি প্রয়োজনীয়ভাবে ফাইলটি মুছে দেয় না - কেবল ডিরেক্টরি থেকে লিঙ্কটি সরিয়ে দেয়।


অন্যদিকে যদি অন্তর্নিহিত ডিভাইস অদৃশ্য হয়ে যায় (যেমন ইউএসবি আনপ্লাগ) তবে ফাইল হ্যান্ডেল আর কার্যকর হবে না এবং কোনও ক্রিয়াকলাপে আইও / ত্রুটি দেওয়ার সম্ভাবনা রয়েছে। আপনি এখনও এটি বন্ধ করতে হবে। ডিভাইসটি আবার প্লাগ ইন করা হলেও এটি সত্য হতে চলেছে, কারণ এই ক্ষেত্রে কোনও ফাইল খোলা রাখা বুদ্ধিমানের নয়।


আমি মনে করি আপনার দ্বিতীয় পয়েন্টটি সমানভাবে প্রযোজ্য যদি ফাইলটির একটি ডিরেক্টরি যুক্ত মুছে ফেলা হয়। তাই নাকি?
ড্রয় নোকস

2
আমি একটি বিষয়ে আগ্রহী: আপনি যদি কোনও ফাইল ওভাররাইট করতে সিপি কমান্ড ব্যবহার করেন তবে এটি কি প্রথম মামলা বা দ্বিতীয় কেস?
xuhdev

1
" শেষ হ্যান্ডেলটি বন্ধ না হওয়া পর্যন্ত ফাইলটি সত্যই মুছে ফেলা হবে না " "আকর্ষণীয়। ধন্যবাদ
জেরেমিয়া

8

ফাইল হ্যান্ডলগুলি কোনও ইনোডের দিকে নির্দেশ করে না কোনও পথ নয়, সুতরাং আপনার বেশিরভাগ পরিস্থিতি এখনও আপনার অনুমানের মতোই কাজ করে, যেহেতু হ্যান্ডেলটি এখনও ফাইলটিতে নির্দেশ করে।

বিশেষত, মুছে ফেলার দৃশ্যের সাথে - ফাংশনটি একটি কারণে "আনলিংক" বলা হয়, এটি একটি ফাইল নাম (একটি দাঁত) এবং একটি ফাইলের মধ্যে একটি "লিঙ্ক" নষ্ট করে দেয়। আপনি যখন কোনও ফাইল খোলেন, তারপরে এটিকে লিঙ্কমুক্ত করুন, ফাইলটি তার রেফারেন্স গণনা শূন্য না হওয়া অবধি প্রকৃতপক্ষে উপস্থিত রয়েছে, যা আপনি হ্যান্ডেলটি বন্ধ করে দিলে।

সম্পাদনা: হার্ডওয়্যারের ক্ষেত্রে, আপনি একটি নির্দিষ্ট ডিভাইস নোডে একটি হ্যান্ডেল খুলেছেন, আপনি যদি ডিভাইসটি প্লাগ প্লাগ করেন তবে কার্নেলটি ডিভাইসটি ফিরে এলেও তার সমস্ত অ্যাক্সেস ব্যর্থ করবে। আপনাকে ডিভাইসটি বন্ধ করে আবার খুলতে হবে।


5

আমি অন্যান্য ক্রিয়াকলাপ সম্পর্কে নিশ্চিত নই, তবে মুছে ফেলার জন্য: ফাইলটির শেষ ওপেন হ্যান্ডেলটি বন্ধ না হওয়া অবধি মুছে ফেলা সহজভাবে হয় না (শারীরিকভাবে, যেমন ফাইল সিস্টেমে)। সুতরাং আপনার আবেদনের আওতায় কোনও ফাইল মুছে ফেলা সম্ভব হবে না।

কয়েকটি অ্যাপ্লিকেশন (যা মনে মনে আসে না) এই আচরণের উপর নির্ভর করে, ফাইলগুলি তৈরি করে, খোলার সাথে সাথে সাথে সাথে মুছে ফেলার মাধ্যমে, যা অ্যাপ্লিকেশনের মতো দীর্ঘকাল বেঁচে থাকে - অন্য অ্যাপ্লিকেশনগুলিকে প্রয়োজন ছাড়াই প্রথম অ্যাপ্লিকেশনটির জীবনকাল সম্পর্কে সচেতন হতে দেয় প্রক্রিয়া মানচিত্র এবং যেমন দেখুন।

অন্যান্য বিষয়গুলির ক্ষেত্রেও একই জাতীয় বিবেচনা প্রযোজ্য।


4

আপনি যদি ফাইল হ্যান্ডলার (ফাইল বর্ণনাকারী) ঠিক আছে কিনা তা পরীক্ষা করতে চান তবে আপনি এই ফাংশনটি কল করতে পারেন।

/**
 * 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;
}

1
if(!fcntl(fd, F_GETFL)) {চেক করার বিষয়টি কী ? আমার ধারণা আপনি EBADFসেখানে খুঁজছেন (আপনি সম্ভবত errno0 থেকে আরম্ভ করতে ভুলে গেছেন )।
উদ্দীপনা

এটি আমার পক্ষে কাজ নয়। open(O_WRONLY|O_APPEND)আমার বর্ণনাকারীটি খোলার সময় আমি - st_nlink সর্বদা থাকুন> = 1 দিয়ে এই পদ্ধতির ব্যবহার করার চেষ্টা করেছি ।
imbearr

2

মোছা ফাইলটির ইন-মেমরি তথ্য (আপনার দেওয়া সমস্ত উদাহরণ মুছে ফেলা ফাইলের উদাহরণ) পাশাপাশি ফাইলটি বন্ধ না হওয়া অবধি আইডোড অন-ডিস্ক অস্তিত্ব থেকে যায়।

হার্ডওয়্যারের hotplugged হচ্ছে একটি সম্পূর্ণ ভিন্ন বিষয়, এবং আপনি দীর্ঘ তবে অন-ডিস্ক inodes অথবা মেটাডাটা পরিবর্তিত হয়েছে আপনার প্রোগ্রাম জীবিত থাকার আশা করা উচিত নয় এ সব


2

নিম্নলিখিত পরীক্ষাগুলি দেখায় যে মার্কআরের উত্তর সঠিক।

code.c:

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

void perror_and_exit() {
  perror(NULL);
  exit(1);
}

int main(int argc, char *argv[]) {
  int fd;
  if ((fd = open("data", O_RDONLY)) == -1) {
    perror_and_exit();
  }
  char buf[5];
  for (int i = 0; i < 5; i++) {
    bzero(buf, 5);
    if (read(fd, buf, 5) != 5) {
      perror_and_exit();
    }
    printf("line: %s", buf);
    sleep(20);
  }
  if (close(fd) != 0) {
    perror_and_exit();
  }
  return 0;
}

ডেটা:

1234
1234
1234
1234
1234

gcc code.cউত্পাদন করতে ব্যবহার করুন a.out। চালান ./a.out। আপনি যখন নিম্নলিখিত ফলাফলটি দেখেন:

line: 1234

rm dataমুছতে ব্যবহার করুন data। তবে ./a.outত্রুটি ছাড়াই চলতে থাকবে এবং নিম্নলিখিত সম্পূর্ণ আউটপুট উত্পাদন করবে:

line: 1234
line: 1234
line: 1234
line: 1234
line: 1234

আমি উবুন্টু 16.04.3 এ পরীক্ষাটি করেছি।


1

/ Proc / ডিরেক্টরিতে আপনি বর্তমানে সক্রিয় প্রতিটি প্রক্রিয়ার একটি তালিকা পাবেন, কেবল আপনার পিআইডি এবং সম্পর্কিত সমস্ত ডেটা রয়েছে তা সন্ধান করুন। একটি ইন্টারেস্টিং তথ্য হ'ল fd / ফোল্ডার, আপনি বর্তমানে প্রক্রিয়া দ্বারা খোলার সমস্ত ফাইল হ্যান্ডেলারগুলি দেখতে পাবেন।

অবশেষে আপনি আপনার ডিভাইসে একটি প্রতীকী লিঙ্কটি খুঁজে পাবেন (/ dev / বা এমনকি / প্রোক / বাস / ইউএসবি / এর আওতায়), যদি ডিভাইসটি স্তব্ধ হয়ে থাকে তবে লিঙ্কটি মারা গেছে এবং এই হ্যান্ডেলটি রিফ্রেশ করা অসম্ভব হবে, প্রক্রিয়াটি অবশ্যই বন্ধ হবে এবং এটি আবার খুলুন (পুনরায় সংযোগ দিয়েও)

এই কোডটি আপনার পিআইডি-র লিঙ্কের বর্তমান অবস্থা পড়তে পারে

#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;
}

এই চূড়ান্ত কোডটি সহজ, আপনি লিঙ্ক্যাট ফাংশন দিয়ে খেলতে পারেন।

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;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.