2009-11-04 40 views
5

Mã của tôi là một cái gì đó như thế này:file Xóa trong khi đọc thư mục với readdir()

DIR* pDir = opendir("/path/to/my/dir"); 
struct dirent pFile = NULL; 
while ((pFile = readdir())) { 
    // Check if it is a .zip file 
    if (subrstr(pFile->d_name,".zip") { 
     // It is a .zip file, delete it, and the matching log file 
     char zipname[200]; 
     snprintf(zipname, sizeof(zipname), "/path/to/my/dir/%s", pFile->d_name); 
     unlink(zipname); 
     char* logname = subsstr(zipname, 0, strlen(pFile->d_name)-4); // Strip of .zip 
     logname = appendstring(&logname, ".log"); // Append .log 
     unlink(logname); 
} 
closedir(pDir); 

(mã này là chưa được kiểm tra và hoàn toàn là một ví dụ)

Vấn đề là: Có được phép xóa một tập tin trong một thư mục trong khi lặp qua thư mục với readdir()? Hoặc sẽ readdir() vẫn tìm thấy tệp .log đã xóa?

Trả lời

5

Trích từ POSIX readdir:

Nếu một tập tin được thêm hay bớt để thư mục sau khi cuộc gọi gần đây nhất để opendir() hoặc rewinddir(), dù một cuộc gọi tiếp theo để readdir() trả lại mục nhập cho tệp đó là không xác định.

Vì vậy, tôi đoán là ... nó phụ thuộc.

Nó phụ thuộc vào hệ điều hành, vào thời gian trong ngày, về trình tự tương đối của các tập tin được thêm/xóa, ...

Và, như một điểm xa hơn, giữa thời điểm readdir() trở về chức năng và bạn cố gắng unlink() tệp, một số quy trình khác có thể đã xóa tệp đó và unlink() của bạn không thành công.


Sửa

Tôi đã thử nghiệm với chương trình này:

#include <dirent.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <unistd.h> 

int main(void) { 
    struct dirent *de; 
    DIR *dd; 

    /* create files `one.zip` and `one.log` before entering the readdir() loop */ 
    printf("creating `one.log` and `one.zip`\n"); 
    system("touch one.log"); /* assume it worked */ 
    system("touch one.zip"); /* assume it worked */ 

    dd = opendir("."); /* assume it worked */ 
    while ((de = readdir(dd)) != NULL) { 
    printf("found %s\n", de->d_name); 
    if (strstr(de->d_name, ".zip")) { 
     char logname[1200]; 
     size_t i; 
     if (*de->d_name == 'o') { 
     /* create `two.zip` and `two.log` when the program finds `one.zip` */ 
     printf("creating `two.zip` and `two.log`\n"); 
     system("touch two.zip"); /* assume it worked */ 
     system("touch two.log"); /* assume it worked */ 
     } 
     printf("unlinking %s\n", de->d_name); 
     if (unlink(de->d_name)) perror("unlink"); 
     strcpy(logname, de->d_name); 
     i = strlen(logname); 
     logname[i-3] = 'l'; 
     logname[i-2] = 'o'; 
     logname[i-1] = 'g'; 
     printf("unlinking %s\n", logname); 
     if (unlink(logname)) perror("unlink"); 
    } 
    } 
    closedir(dd); /* assume it worked */ 
    return 0; 
} 

Trên máy tính của tôi, readdir() tìm thấy tập tin đã xóa và không tìm thấy file tạo ra giữa opendir()readdir(). Nhưng nó có thể khác trên máy tính khác; nó có thể khác trên máy tính của tôi nếu tôi biên dịch với các tùy chọn khác nhau; nó có thể khác nếu tôi nâng cấp hạt nhân; ...

+1

LOL @ 'man 2 readdir':" Đây không phải là chức năng bạn quan tâm. " – pmg

+1

Cùng một trang người đàn ông nói: "Mục nhập thư mục đại diện cho tệp; tệp có thể bị xóa khỏi thư mục hoặc được thêm vào thư mục không đồng bộ với hoạt động của readdir()" Nhưng có thể tránh điều này tốt hơn !? – To1ne

1

Tôi đang thử nghiệm sách tham khảo mới của Linux. Giao diện lập trình Linux của Michael Kerrisk và nó nói như sau:

SUSv3 lưu ý một cách rõ ràng rằng readdir() sẽ trả lại tên tệp đã được thêm vào hoặc bị xóa khỏi lần cuối kể từ lần gọi cuối cùng đến opendir() hoặc rewinddir(). Tất cả các tên tệp không được thêm vào cũng không bị xóa kể từ lần gọi gần nhất là đảm bảo được trả lại.

Tôi nghĩ rằng những gì không xác định là những gì xảy ra với các hướng dẫn chưa được quét. Khi một mục nhập đã được trả lại, nó được đảm bảo 100% rằng nó sẽ không được trả lại nữa cho dù bạn có hủy liên kết dirent hiện tại hay không.

Cũng lưu ý bảo lãnh được cung cấp bởi câu thứ hai.Vì bạn đang để lại một mình các tệp khác và chỉ hủy liên kết mục nhập hiện tại cho tệp zip, SUSv3 đảm bảo rằng tất cả các tệp khác sẽ được trả về. Điều gì xảy ra với tệp nhật ký là không xác định. nó có thể hoặc không thể được trả lại bởi readdir() nhưng trong trường hợp của bạn, nó không nên có hại.

Lý do tại sao tôi đã khám phá câu hỏi đó là tìm một cách hiệu quả để đóng các bộ mô tả tệp trong một tiến trình con trước exec().

Cách đề xuất trong APUE từ Stevens là phải làm như sau:

int max_open = sysconf(_SC_OPEN_MAX); 
for (int i = 0; i < max_open; ++i) 
    close(i); 

nhưng tôi đang nghĩ đến việc sử dụng mã tương tự như những gì được tìm thấy trong OP để quét/dev/fd/thư mục để biết chính xác fds tôi cần phải đóng. (Lưu ý đặc biệt cho bản thân mình, bỏ qua dirfd có trong tay cầm DIR.)

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