Để xác định xem tệp F có nằm trong thư mục D, trước tiên là D để xác định số thiết bị và số inode (thành viên st_dev và st_ino của struct stat).
Sau đó, chỉ số F để xác định xem đó có phải là một thư mục hay không. Nếu không, hãy gọi tên cơ sở để xác định tên của thư mục chứa nó. Đặt G thành tên của thư mục này. Nếu F đã là một thư mục, hãy đặt G = F.
Bây giờ, F nằm trong D nếu và chỉ khi G nằm trong D. Tiếp theo chúng ta có vòng lặp.
while (1) {
if (samefile(d_statinfo.d_dev, d_statinfo.d_ino, G)) {
return 1; // F was within D
} else if (0 == strcmp("/", G) {
return 0; // F was not within D.
}
G = dirname(G);
}
Chức năng samefile rất đơn giản:
int samefile(dev_t ddev, ino_t dino, const char *path) {
struct stat st;
if (0 == stat(path, &st)) {
return ddev == st.st_dev && dino == st.st_no;
} else {
throw ...; // or return error value (but also change the caller to detect it)
}
}
này sẽ làm việc trên hệ thống tập tin POSIX. Nhưng nhiều hệ thống tập tin không phải là POSIX. Các vấn đề cần tìm kiếm bao gồm:
- Hệ thống tệp nơi thiết bị/inode không phải là duy nhất. Một số hệ thống tập tin FUSE là những ví dụ về điều này; đôi khi chúng tạo nên số inode khi các hệ thống tệp cơ bản không có chúng. Họ không nên sử dụng lại số inode, nhưng một số hệ thống tập tin FUSE có lỗi.
- Triển khai NFS bị hỏng. Trên một số hệ thống, tất cả các hệ thống tệp NFS có cùng số thiết bị. Nếu chúng vượt qua số inode như nó tồn tại trên máy chủ, điều này có thể gây ra một vấn đề (mặc dù tôi chưa bao giờ thấy nó xảy ra trong thực tế).
- Linux ràng buộc các điểm gắn kết. Nếu
/a
là gắn kết gắn kết của /b
, thì /a/1
có vẻ như nằm bên trong /a
, nhưng với việc triển khai ở trên, /b/1
cũng xuất hiện bên trong /a
. Tôi nghĩ đó có lẽ là câu trả lời đúng. Tuy nhiên, nếu đây không phải là kết quả bạn thích, điều này có thể dễ dàng được sửa bằng cách thay đổi trường hợp return 1
để gọi số strcmp()
để so sánh tên đường dẫn. Tuy nhiên, để làm việc này, bạn sẽ cần phải bắt đầu bằng cách gọi số realpath
trên cả F và D. Cuộc gọi realpath
có thể khá tốn kém (vì có thể cần phải truy cập đĩa nhiều lần).
- Đường dẫn đặc biệt
//foo/bar
. POSIX cho phép tên đường dẫn bắt đầu bằng //
là đặc biệt theo cách không được xác định rõ ràng. Thực ra tôi quên mức độ bảo đảm chính xác về ngữ nghĩa mà POSIX cung cấp. Tôi nghĩ rằng POSIX cho phép //foo/bar
và //baz/ugh
để chỉ cùng một tệp. Kiểm tra thiết bị/inode vẫn nên làm điều phù hợp với bạn nhưng bạn có thể không tìm thấy nó (tức là bạn có thể thấy rằng //foo/bar
và //baz/ugh
có thể tham chiếu cùng một tệp nhưng có số thiết bị/số inode khác nhau).
câu trả lời này giả định rằng chúng ta bắt đầu với một đường dẫn tuyệt đối cho cả F và D. Nếu điều này không được bảo đảm bạn có thể cần phải làm một số chuyển đổi sử dụng realpath()
và getcwd()
. Đây sẽ là một vấn đề nếu tên của thư mục hiện tại dài hơn PATH_MAX
(điều này chắc chắn có thể xảy ra).
Nguồn
2011-08-31 20:00:46
Tôi nghĩ đây là lý do 'chroot (2)' được phát minh! –
@Carl Norum: chroot tốt hơn nếu bạn cấp cho ai đó quyền truy cập shell giới hạn. nếu bạn không muốn giới hạn quyền truy cập vào một chương trình bạn tạo, có những lựa chọn tốt hơn so với chroot. – Dani