2010-01-08 15 views
66

gì xảy ra với một trình xử lý tập tin mở trên Linux nếu file nhọn trong khi đó nhận được:gì xảy ra với một trình xử lý tập tin mở trên Linux nếu file nhọn được di chuyển, xóa

  • chuyển đi -> Liệu trình điều khiển file vẫn hợp lệ?
  • Đã xóa -> Điều này có dẫn đến EBADF, cho biết trình xử lý tệp không hợp lệ không?
  • Được thay thế bởi một tệp mới -> Trình xử lý tệp có trỏ đến tệp mới này không?
  • Thay thế bằng liên kết cứng đến tệp mới -> Trình xử lý tệp của tôi có "theo dõi" liên kết này không?
  • Thay thế bằng liên kết mềm thành tệp mới -> Trình xử lý tệp của tôi có nhấn vào tệp liên kết mềm này ngay bây giờ không?

Tại sao tôi hỏi những câu hỏi như vậy: Tôi đang sử dụng phần cứng được cắm nóng (chẳng hạn như thiết bị USB, v.v.). Nó có thể xảy ra, rằng thiết bị (và cũng là/dev/file) được người dùng hoặc một Gremlin khác gắn lại.

Cách tốt nhất để giải quyết vấn đề này là gì?

Trả lời

96

Nếu tệp được di chuyển (trong cùng hệ thống tệp) hoặc đổi tên, thì xử lý tệp vẫn mở và vẫn có thể được sử dụng để đọc và ghi tệp.

Nếu tệp bị xóa, xử lý tệp vẫn mở và vẫn có thể được sử dụng (Đây không phải là điều mà một số người mong đợi). Các tập tin sẽ không thực sự bị xóa cho đến khi xử lý cuối cùng được đóng lại.

Nếu tệp được thay thế bằng tệp mới, tệp đó phụ thuộc chính xác như thế nào. Nếu nội dung của tệp bị ghi đè, xử lý tệp sẽ vẫn hợp lệ và truy cập nội dung mới. Nếu tệp hiện có được hủy liên kết và tệp mới được tạo có cùng tên hoặc, nếu tệp mới được di chuyển sang tệp hiện có bằng cách sử dụng rename(), nó giống như xóa (xem ở trên) - tức là, trình xử lý tệp sẽ tiếp tục tham chiếu vào phiên bản gốc của tệp. Nói chung, khi tệp đang mở, tệp sẽ mở và không ai thay đổi cấu trúc thư mục có thể thay đổi điều đó - chúng có thể di chuyển, đổi tên tệp hoặc đặt một thứ khác vào vị trí của nó, đơn giản là nó vẫn mở.

Trong Unix không có xóa, chỉ unlink(), có ý nghĩa vì nó không nhất thiết phải xóa tệp - chỉ cần xóa liên kết khỏi thư mục.


Nếu mặt khác các thiết bị cơ bản biến mất (ví dụ USB rút phích cắm điện) sau đó các tập tin xử lý sẽ không có giá trị nữa và có khả năng cung cấp cho IO/lỗi trên bất kỳ hoạt động. Bạn vẫn phải đóng nó mặc dù. Điều này sẽ đúng ngay cả khi thiết bị được cắm lại, vì nó không hợp lý để giữ một tập tin mở trong trường hợp này.

+0

Tôi cho rằng điểm thứ hai của bạn được áp dụng như nhau nếu thư mục chứa tệp bị xóa. Là vậy sao? –

+1

Tôi quan tâm đến một điều: nếu bạn sử dụng lệnh cp để ghi đè lên một tệp, đó có phải là trường hợp đầu tiên hoặc trường hợp thứ hai không? – xuhdev

1

Thông tin trong bộ nhớ của tệp đã xóa (tất cả các ví dụ bạn cung cấp là các phiên bản của tệp đã xóa) cũng như các inodes trên đĩa vẫn tồn tại cho đến khi tệp được đóng.

Phần cứng đang được cắm nóng là một vấn đề hoàn toàn khác và bạn không nên mong đợi chương trình của mình vẫn hoạt động lâu nếu các inode hoặc siêu dữ liệu trên đĩa đã thay đổi ở tất cả.

5

Xử lý tệp trỏ đến một inode chứ không phải đường dẫn, vì vậy hầu hết các trường hợp của bạn vẫn hoạt động như bạn giả định, vì tay cầm vẫn trỏ đến tệp.

Cụ thể, với trường hợp xóa - chức năng được gọi là "hủy liên kết" vì lý do, nó phá hủy "liên kết" giữa tên tệp (răng giả) và tệp. Khi bạn mở một tệp, sau đó hủy liên kết tệp, tệp thực sự vẫn tồn tại cho đến khi số tham chiếu của nó chuyển thành 0, đó là khi bạn đóng tay cầm.

Chỉnh sửa: Trong trường hợp phần cứng, bạn đã mở một tay cầm vào một nút thiết bị cụ thể, nếu bạn rút phích cắm thiết bị, hạt nhân sẽ không truy cập được vào thiết bị, ngay cả khi thiết bị quay lại. Bạn sẽ phải đóng thiết bị và mở lại thiết bị.

2

Tôi không chắc chắn về các thao tác khác, nhưng để xóa: Xóa đơn giản là không diễn ra (về mặt vật lý, tức là trong hệ thống tệp) cho đến khi xử lý mở cuối cùng cho tệp được đóng. Do đó, bạn không thể xóa một tệp ra khỏi ứng dụng của mình. Một vài ứng dụng (không lưu ý) dựa vào hành vi này, bằng cách tạo, mở và xóa ngay lập tức các tệp, sau đó sống chính xác miễn là ứng dụng - cho phép các ứng dụng khác biết về ứng dụng đầu tiên vòng đời mà không cần phải nhìn vào bản đồ quy trình và như vậy.

Có thể những cân nhắc tương tự có thể áp dụng cho các nội dung khác.

1

Dưới thư mục/proc/bạn sẽ tìm thấy danh sách của mọi quá trình hiện đang hoạt động, chỉ cần tìm PID của bạn và tất cả dữ liệu liên quan là có. Một thông tin liên tục là thư mục fd /, bạn sẽ tìm thấy tất cả các trình xử lý tệp hiện đang được mở bởi quy trình.

Cuối cùng, bạn sẽ tìm thấy một liên kết tượng trưng cho thiết bị của bạn (dưới/dev/hoặc thậm chí/proc/bus/usb /), nếu thiết bị treo liên kết sẽ chết và sẽ không thể làm mới xử lý này, quá trình phải đóng và mở lại (ngay cả với kết nối lại)

mã này có thể đọc liên kết hiện trạng của PID của bạn

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

mã cuối cùng này rất đơn giản, bạn có thể chơi với chức năng 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

nếu bạn muốn kiểm tra xem trình xử lý tệp (bộ mô tả tệp) có được không, bạn có thể gọi hàm này.

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

Điểm của 'if (! Fcntl (fd, F_GETFL)) {' kiểm tra là gì? Tôi đoán bạn đang tìm kiếm 'EBADF' ở đó. (Bạn cũng có thể quên khởi tạo 'errno' thành 0). – woky

Các vấn đề liên quan