Một tập tin có thể được lấy bằng inode của nó?


27

Tôi đã chạy các lệnh theo thứ tự được chỉ định:

$ln a b
$ls -i a b
523669 a 523669 b
$rm -f a
$ls -i b
523669 b

Tôi đã kết luận từ thử nghiệm này rằng lệnh rmthực sự chỉ xóa tên tệp ( atrong thử nghiệm này) thay vì tệp, vì inode vẫn tồn tại và có thể được truy xuất thông qua tên tệp khác ( b).

Câu hỏi của tôi là, nếu một tệp được liên kết cứng với chỉ một tên tệp, khi rmđược thực thi với tệp, liệu tệp thực (tức là inode) có bị xóa hoàn toàn không? Và nếu không, một tập tin inode có thể được lấy mà không có tên tệp và chỉ thông qua các nút?


Âm thanh đặc trưng cho hệ điều hành đối với tôi.
Ignacio Vazquez-Abrams

@Ignacio Vazquez-Abrams. Bạn có nghĩa là nó phụ thuộc vào phiên bản?
user43312

Không, ý tôi là nó phụ thuộc vào hệ điều hành. Mỗi cách có cách khác nhau (nếu ) để khai thác vào VFS.
Ignacio Vazquez-Abrams

@Ignacio Vazquez-Abrams Bạn có ý tưởng gì về RHL hoặc RHEL không?
user43312

1
@BruceEdiger Os X sắp xếp thứ đó. Bạn có thể truy cập một đối tượng hệ thống tệp bằng cách sử dụng "URL tham chiếu tệp", về cơ bản, được xây dựng từ số hệ thống tệp và số nút. Tuy nhiên, nó không được hỗ trợ chính thức để tự xây dựng chúng. Thay vào đó, bạn có được "URL tham chiếu tệp" cho một tệp và sau đó sử dụng nó thay vì tên đường dẫn cho các lần truy cập tiếp theo trong cùng một phiên thời gian chạy để ứng dụng của bạn trở nên lãng quên khi tệp được di chuyển ở nơi khác trên cùng một ổ đĩa.
Tệp tương tự

Câu trả lời:


29

Nếu bạn cố gắng mở một tệp thông qua inode của nó, điều này sẽ bỏ qua mọi thư mục truyền tải. Thư mục truyền tải là cần thiết để xác định các quyền của tệp và thư mục dẫn đến nó. Không có thư mục truyền tải, kernel không có cách nào để xác định liệu quy trình gọi có được phép truy cập tệp hay không.

Có một bản vá được đề xuất cho nhân Linux để cho phép tạo một liên kết đến một tệp từ một bộ mô tả tệp . Nó đã bị từ chối vì thực hiện điều này một cách an toàn sẽ vô cùng khó khăn .

Trong Linux (và có thể trên các biến thể unix khác vì lý do tương tự), bạn không thể tạo liên kết đến tệp đã bị xóa, vì vậy nếu tệp không còn tên, bạn không thể thêm lại. tập tin bằng cách mở các liên kết ma thuật dưới /proc/$pid/fd/.

Nếu một tệp không còn bất kỳ liên kết nào và không còn mở nữa, nó không còn tồn tại và không gian trước đây được sử dụng bởi dữ liệu của nó có thể được lấy lại bất cứ lúc nào.

¹ Bạn có thể làm điều này bằng twiddling các byte trực tiếp trong hệ thống tập tin theo một cách hệ thống tập tin phụ thuộc vào, ví dụ với debugfscho ext2 / ext3 / ext4. Điều này đòi hỏi quyền truy cập vào thiết bị mà hệ thống tập tin được gắn kết (nghĩa là chỉ có root mới có thể thử nó). Tuy nhiên, trong khi gỡ lỗi có thể truy cập tệp bằng inode, điều này không hữu ích nếu tệp bị xóa: tệp sẽ thực sự bị xóa nếu ứng dụng đóng nó và chạy gỡ lỗi trong chế độ đọc ghi trên hệ thống tệp được gắn là một công thức cho thảm họa.


11

Trên Linux, debugfstrình gỡ lỗi hệ thống tệp ext2 / ext3 / ext4 tương tác cung cấp một lnlệnh có thể lấy số inode filespecvà tạo một liên kết cứng mới đến tệp tương ứng. Trong thực tế, điều này đòi hỏi tệp không được liên kết được giữ theo một quy trình , duy trì một bộ mô tả tệp mở /proc/[pid]/fd/[n]. Cố gắng điều này là trên một tập tin bị xóa rất có thể sẽ dẫn đến tham nhũng hệ thống tập tin.

Điều này là do để đảm bảo rằng ext3 (và trong phần mở rộng ext4) có thể khôi phục lại một liên kết một cách an toàn sau khi gặp sự cố, nó thực sự loại bỏ các con trỏ khối trong inode , trong khi ext2 chỉ đánh dấu các khối này là không được sử dụng trong bitmap khối và đánh dấu inode là "đã xóa" và để lại các con trỏ khối một mình. Mặc dù vậy, vì hệ thống tệp cần được gắn đọc-ghi để tạo liên kết cứng, các khối dành riêng cho tệp đã xóa có thể đã được phân bổ lại.

Trước phiên bản kernel 2.6.39, tùy chọn được giới thiệu trong GNU coreutils v8.0 có thể được sử dụng để khôi phục tệp không được liên kết thông qua một bộ mô tả tệp mở trong nếu cả tệp không được liên kết và liên kết cứng mới nằm trong hệ thống tệp tmpfs . Khả năng này đã bị vô hiệu hóa , do, như Gilles đã chỉ ra, các cân nhắc bảo mật liên quan đến việc cho phép tạo liên kết cứng trực tiếp từ một bộ mô tả tệp.ln -L|--logical/proc/[pid]/fd/[n]


Tôi vừa thử sử dụng ln -Lđể khôi phục một tệp đã bị xóa từ / Proc và gặp lỗi: "Không có tệp hoặc thư mục như vậy", vì vậy tôi không nghĩ rằng nó thực sự hỗ trợ điều này. Tôi có coreutils 8.21.
wingbedubmariner

1
ln -Lkhông làm những gì bạn nói nó làm. Nó nói lnrằng nếu nguồn là một liên kết tượng trưng, ​​thì nó sẽ cứng liên kết mục tiêu. Các liên kết tượng trưng /proc/$pid/fdlà đặc biệt và liên kết cứng (deleted)không liên kết.
Gilles 'SO- ngừng trở nên xấu xa'

Cũng debugfssẽ không hữu ích nếu tệp đã bị xóa - trừ khi bạn muốn mạo hiểm chạy nó ở chế độ đọc ghi trên hệ thống tệp được gắn, có khả năng sẽ xử lý hoàn toàn toàn bộ hệ thống tệp.
Gilles 'SO- ngừng trở nên xấu xa'

Cập nhật câu trả lời liên quan đến ln -L. Nó đã từng có thể tạo các liên kết cứng từ /proc/[pid]/fd/[n]việc sử dụng nó trong một số trường hợp đặc biệt, nhưng điều này đã được sửa chữa.
Thomas Nyman

1
debugfs's lnlà mức độ thực sự thấp và chỉ tạo ra một cái tên, không cập nhật số lượng cũng không unmarks các khối như chưa sử dụng vì vậy nó rất nguy hiểm . Thích debugfs's undelmà des tất cả điều đó. Cảnh báo: debugfsđược không được chạy trên một hệ thống tập tin được gắn trừ khi bạn muốn để có một cơ hội đốt FS của bạn thành tro bụi.
Lloeki

9

Các lệnh 'ln' và 'rm' đã hoạt động chính xác như thế này trong mọi hệ thống tệp UNIX kể từ đầu những năm 1970. Mac OSX, BSD và Linux đều kế thừa thiết kế ban đầu này.

Chính nó, một tập tin UNIX không có tên, chỉ có một số inode hoặc inum. Nhưng bạn chỉ có thể truy cập nó thông qua một mục trong tệp "thư mục" đặc biệt có liên kết tên với inum trong câu hỏi; bạn không thể chỉ định inum trực tiếp.

Một thư mục tự nó là một tệp, vì vậy bạn cũng phải truy cập qua thư mục (khác), v.v., thông qua một loạt các tên thư mục được phân định bằng dấu gạch chéo (/) được gọi là "tên đường dẫn". Một đường dẫn bắt đầu trong "thư mục làm việc hiện tại" của quy trình trừ khi tên bắt đầu bằng "/", trong trường hợp đó, nó bắt đầu bằng thư mục gốc của hệ thống tệp. Ví dụ, nếu tên đường dẫn không chứa ký tự "/", thì nó được dự kiến ​​là một mục trong thư mục hiện tại.

Một tệp không phải thư mục có thể có bất kỳ số lượng tên đường dẫn, được gọi là "liên kết cứng" và nó sẽ tiếp tục tồn tại cho đến khi tất cả các tên đường dẫn của nó đã bị xóa quá trình cuối cùng đã đóng tệp. Sau đó, tập tin thực sự bị xóa và không gian của nó được đánh dấu là có sẵn để sử dụng lại. Nghĩa là, bạn có thể tạo () hoặc mở () tệp liên kết đơn và sau đó hủy liên kết () để nó không còn xuất hiện trong không gian tên hệ thống tệp, nhưng tệp sẽ tiếp tục tồn tại cho đến khi bạn đóng tệp. Điều này hữu ích cho các tệp cào tạm thời không được đọc bởi bất kỳ chương trình nào khác.

Mặc dù các thư mục có số inode, hầu hết các hệ thống tệp không cho phép liên kết cứng đến chúng; chúng chỉ có thể xuất hiện trong một thư mục khác. (Một ngoại lệ khác thường là hệ thống tệp Mac OSX HFS +; điều này cho phép sao lưu Time Machine hoạt động.) Bạn vẫn có thể tạo "liên kết mềm" cho các thư mục (hoặc bất kỳ tệp nào khác). Một liên kết mềm giống như một mục nhập thư mục ngoại trừ việc nó chứa một tên đường dẫn khác chứ không phải là một inum.

Mỗi tệp UNIX có quyền sở hữu, nhóm và quyền truy cập. Điều đó là cần thiết nhưng không đủ để họ cho phép bạn mở tệp; bạn cũng phải có ít nhất quyền thực thi cho mọi thư mục trong tên đường dẫn bạn sử dụng để tham chiếu đến nó. Đó là lý do tại sao không có cách chuẩn để mở tệp UNIX bằng số inode của nó; điều đó sẽ bỏ qua một cơ chế bảo mật quan trọng, được sử dụng rộng rãi.

Nhưng điều này không giải thích được tại sao không thể có một cách tiêu chuẩn để người dùng root (đặc quyền) mở tệp bằng số inode, vì dù sao việc kiểm tra quyền cũng bị bỏ qua. Điều này sẽ rất hữu ích cho các chức năng quản lý hệ thống nhất định như sao lưu. Theo hiểu biết của tôi, các cơ chế như vậy tồn tại, nhưng tất cả chúng đều dành riêng cho hệ thống tệp; không có cách chung nào để làm điều đó cho bất kỳ hệ thống tập tin UNIX nào.


1
Việc chuyển tiếp /là im lặng, do đó, nó được phát âm là slash.
ctrl-alt-delor

4

Câu hỏi có thể được thực hiện trên lý thuyết (có thể đạt được debugfs) hoặc thực tế (tình huống khẩn cấp). Trong trường hợp sau, tôi cho rằng mục đích là tiết kiệm trong ngày và khôi phục nội dung của tệp, có thể là khẩn cấp (đó là cách tôi tiếp cận câu hỏi này, vì vậy tôi nghĩ rằng nó vẫn có liên quan và hữu ích).

Vì không có API kernel, debugfskhông nên chạy trên hệ thống tệp trực tiếp vì nó thao túng trực tiếp cấu trúc FS. Do đó, để thực hiện nó trực tiếp, bạn phải có một tên tệp khác. Giả sử tệp vẫn đang mở bởi một số quy trình (bất kỳ quy trình nào), người ta có thể tiếp cận với các mô tả tệp tiện lợi chưa từng có trong /proc:

$ lsof -F pf "$PWD/a" | sed 's/^p//' # find pid and file descriptor number of any process having the file open
$ pid=1234
$ ls -l /proc/$pid/fd/* | grep "$PWD/a" # find file descriptor number
$ fd=42
$ cat /proc/$pid/fd/$fd > "$PWD/a.restored" # read contents to a new filename

Lời khuyên:

  • Nếu bạn nghi ngờ về fd đúng, bạn có thể chạy các lệnh như filetrên nó
  • nếu có một quy trình ghi vào tệp, hãy chắc chắn dừng quá trình đó càng sớm càng tốt hoặc bạn sẽ không nhận được dữ liệu mới nhất. Một mẹo (chưa được kiểm tra) có thể là mở tệp chỉ đọc qua fd với một số quy trình khác (thử tail -f < /proc/$pid/fd/$fd > /dev/null, thoát khỏi quá trình viết để nó thoát ra một cách sạch sẽ và sử dụng fd của quy trình mới.

2
Đó nên là tail -f < /proc/...trong mẹo thứ hai.
Murray Jensen

Hoặc sử dụng tail -c +0 -f để sao chép nó ở vị trí đầu tiên thay vì cat, nếu quá trình viết chỉ là nối thêm (không tìm kiếm lại và viết lại). Thoát khỏi quá trình khác trước tail, sau đó chờ đợi tailđể đến cuối tập tin.
Peter Cordes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.