2013-06-15 31 views
14

Nếu tôi có một xử lý cho một tệp đang mở, có thể tạo liên kết cứng tới tệp đó sau khi tất cả các tham chiếu đến tệp đó đã bị xóa khỏi hệ thống tệp không?Tạo một liên kết cứng từ một tập tin xử lý trên Unix?

Ví dụ, một cái gì đó như thế này:

fd = fopen("/tmp/foo", "w"); 
unlink("/tmp/foo"); 
fwrite(fd, "Hello, world!\n"); 
create_link_from_fd(fd, "/tmp/hello"); 
fclose(fd); 

Cụ thể, tôi muốn làm điều này vì vậy mà tôi có thể yên tâm gửi thư cho các file dữ liệu lớn, sau đó di chuyển chúng vào đúng vị trí nguyên tử mà không cần phải lo lắng về việc làm sạch lên sau bản thân mình nếu chương trình của tôi bị giết ở giữa ghi tệp.

+0

câu hỏi hay, +1 – nsd

Trả lời

2

Không nói chung, không có. [Chỉnh sửa: kể từ Linux 3.11 hiện có linkat; xem safsaf32's answer. Điều này không hoạt động trên các hệ thống POSIX nói chung vì POSIX linkat chỉ giới hạn ở các thư mục.] Có những cân nhắc về bảo mật ở đây: ai đó có thể chuyển cho bạn một bộ mô tả tệp mở mà bạn không thể tự mình làm như bình thường

mkdir lock; chmod 700 lock 
echo secret contents > lock/in 
sudoish cmd < lock/in 

Ở đây cmd chạy với tư cách người dùng không có quyền đối với open tệp đầu vào (lock/in) theo tên nhưng vẫn có thể đọc từ đó. Nếu cmd có thể tạo tên mới trên cùng một hệ thống tệp, nó có thể chuyển nội dung tệp vào quy trình sau. (Rõ ràng là nó có thể sao chép những nội dung đó, do đó, vấn đề này là nhiều hơn "vượt qua nội dung trên do nhầm lẫn" điều hơn là "chuyển nội dung trên, có mục đích".)

Điều đó nói rằng, mọi người đã tìm ra cách "relinking" các tập tin bằng inode/vnode nội bộ (nó khá dễ dàng để làm bên trong hầu hết các hệ thống tập tin), vì vậy bạn có thể làm cho hệ thống riêng của bạn gọi cho nó. Bộ mô tả phải đề cập đến một tập tin thực sự trên điểm lắp thích hợp, tất nhiên - không có cách nào "tiếp tục" một đường ống hoặc ổ cắm hoặc thiết bị để trở thành một tập tin thông thường.

Nếu không, bạn bị mắc kẹt với "tín hiệu bắt và dọn dẹp và hy vọng điều tốt nhất", hoặc mẹo tương tự ", tắt một tiến trình con, chạy nó và nếu thành công/thất bại, hãy di chuyển/làm sạch thích hợp- lên hành động ".


Chỉnh sửa để thêm chú thích lịch sử: trên lock ví dụ là không đặc biệt tốt, nhưng trở lại trong những ngày của V6 Unix, MDQS sử dụng một phiên bản fancier của thủ thuật này. Các bit và các phần của MDQS tồn tại dưới nhiều hình thức khác nhau ngày nay.

2

Trên Linux, bạn có thể thử các trick unportable của việc sử dụng /proc/self/fd bằng cách cố gắng gọi

char pbuf[64]; 
snprintf (pbuf, sizeof(pbuf), "/proc/self/fd/%d", fd); 
link(pbuf, "/tmp/hello"); 

Tôi sẽ ngạc nhiên nếu lừa mà làm việc sau khi một unlink("/tmp/foo") ... Tôi không cố gắng đó.

Một cách cầm tay hơn (nhưng ít mạnh mẽ) sẽ là để tạo ra một "con đường tạm độc đáo" có lẽ như

int p = (int) getpid(); 
int t = (int) time(0); 
int r = (int) random(); 
sprintf(pbuf, sizeof(pbuf), "/tmp/out-p%d-r%d-t%d.tmp", p, r, t); 
int fd = open (pbuf, O_CREAT|O_WRONLY); 

Một khi tập tin đã được viết và đóng lại, bạn rename(2) nó để một số con đường hợp lý hơn. Bạn có thể sử dụng atexit trong chương trình của mình để thực hiện việc đổi tên (hoặc xóa).

Và có một số cron công việc để làm sạch [cũ] /tmp/out*.tmp mỗi giờ ...

+0

Thủ thuật này không hoạt động, thật không may (ít nhất là đối với tôi!). – Celada

8

Linux vừa được phát hành 3.11 cung cấp giải pháp cho vấn đề này với cờ O_TMPFILEopen(2) mới. Với cờ này, bạn có thể tạo một tệp "vô hình" (tức là một inode không có hardlinks) trong một số hệ thống tệp (được chỉ định bởi một thư mục trong hệ thống tệp đó). Sau đó, sau khi tệp được thiết lập đầy đủ, bạn có thể tạo liên kết cứng bằng cách sử dụng linkat. Nó hoạt động như thế này:

fd = open("/tmp", O_TMPFILE | O_RDWR, 0600); 
// write something to the file here 
// fchown()/fchmod() it 
linkat(fd, "", AT_FDCWD, "/tmp/test", AT_EMPTY_PATH); 

Lưu ý rằng ngoài yêu cầu kernel> = 3,11, điều này cũng đòi hỏi phải có sự hỗ trợ từ hệ thống tập tin cơ bản (Tôi đã thử đoạn mã trên vào ext3 và nó làm việc, nhưng nó dường như không làm việc trên btrfs).

+0

Điều này hoạt động hoặc sử dụng '/ proc/self/fd/n', được chứng minh bởi http://comments.gmane.org/gmane.linux.file-systems/76553 –

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