Tại sao lại không thể xóa thư mục này?


12

Tôi có một thư mục có -wxquyền được gọi folder1và một thư mục khác bên trong nó được gọi folder2với rwxquyền.

Tôi đã cố gắng xóa folder1bằng lệnh này:

rm -r folder1

Nhưng tôi đã nhận được lỗi sau:

rm: cannot remove 'folder1': Permission denied

Lý do tôi nghĩ rằng tôi đã gặp lỗi này là vì rmtrước tiên chương trình cần lấy nội dung của folder1(lấy tên của các tệp và thư mục bên trong folder1) để có thể xóa nội dung đó (vì bạn không thể xóa tệp hoặc thư mục mà tôi không biết tên của nó tôi nghĩ), và sau đó rmchương trình có thể folder1tự xóa .

Nhưng vì folder1không có sự readcho phép, nên rmchương trình không thể lấy nội dung của nó và do đó nó không thể xóa nội dung của nó và vì nó không thể xóa nội dung của nó, nên nó không thể xóa nội dung đó.

Tôi có đúng không?


1
Làm "ls -l" và cho chúng tôi biết các quyền của TRỰC TIẾP là gì.
jamesqf

Câu trả lời:


19

Tôi nghĩ rằng phân tích của bạn là chính xác: bạn không thể xóa thư mục vì nó không trống và bạn không thể làm trống nó vì bạn không thể thấy nội dung của nó.

Tôi chỉ thử nó:

$ mkdir -p folder1/folder2
$ chmod -r folder1
$ rm -rf folder1
rm: cannot remove 'folder1': Permission denied
$ rmdir folder1/folder2
$ rm -rf folder1
$ 

Khi tôi viết bài của bạn, tôi có nghĩa là bất kỳ chương trình nào bạn có thể chạy. rm -rLệnh của bạn trước tiên nhìn thấy đó folder1là một thư mục, vì vậy nó cố gắng khám phá nội dung của nó để làm trống nó, nhưng không thể thiếu quyền đọc, sau đó nó cố xóa nó nhưng không thành công vì nó không trống. Giấy phép từ chối từ chối là sai lệch; Tôi nghĩ rằng Thư mục của Nhật Bản không trống rỗng (như rmdirbáo cáo) sẽ phù hợp hơn.)


4
Nó không thể báo cáo Directory not emptytrong trường hợp này vì nó sẽ không biết nó trống hay không. Bạn vẫn sẽ gặp lỗi tương tự khi cố gắng xóa một thư mục trống mà bạn không có quyền đọc. (Ngoài ra, vui lòng bỏ qua nhận xét trước đây của tôi, tôi không có tư duy của mình trên).
Kusalananda

1
@Kusalananda Nghe có vẻ lành mạnh, nhưng rmdircó thể báo cáo Thư mục của Cameron không trống rỗng. Và nếu bạn đọc bài kiểm tra của tôi, bạn sẽ thấy rằng nó chấp nhận xóa folder1thư mục, không có quyền đọc , một khi tôi đã xóa nó.
dùng2233709

2
Thử nghiệm của bạn cho thấy một sự khác biệt thú vị giữa các hệ thống của chúng tôi. Tôi nhận được Permission deniedkhi cố gắng rm -r folder1khi nó trống rỗng. Tôi đang dùng OpenBSD, không phải Linux.
Kusalananda

@Kusalananda Thật thú vị. Tôi đã nghĩ rằng hành vi này được chỉ định bởi Thông số kỹ thuật Unix đơn, do đó, BSD của Linux và {Free, Net, Open} sẽ hoạt động giống hệt nhau. (Đối với bản ghi, tôi đang sử dụng Debian Stretch 9.8 với kernel linux 4.9.144-3 x86_64.)
user2233709

Hmm ... Điều duy nhất mà POSIX nói là nếu toán hạng là một thư mục và -rđược sử dụng, mỗi mục nhập thư mục (ngoại trừ ...) phải được loại bỏ như thể chúng là toán hạng của tệp rm -r. Nó xuất hiện như thể GNU rmchỉ đơn giản thực hiện một rmdir()thư mục nếu nó không thể đọc được, bởi vì nó sẽ không có cách nào để có được nội dung của nó.
Kusalananda

7

Để xóa xảy ra, hệ thống phải có khả năng đọc nội dung và xác định những gì phải xóa.

Tôi đã thử mô phỏng những gì bạn đang cố gắng:

[vagrant@desktop1 ~]$ sudo rm -rf folder1/ && mkdir -pv folder1/folder2 && sudo chmod 333 -v folder1/ && sudo chmod 777 -v folder1/folder2
mkdir: created directory 'folder1'
mkdir: created directory 'folder1/folder2'
mode of 'folder1/' changed from 0775 (rwxrwxr-x) to 0333 (-wx-wx-wx)
mode of 'folder1/folder2' changed from 0775 (rwxrwxr-x) to 0777 (rwxrwxrwx)
[vagrant@desktop1 ~]$ ls -lh
total 0
d-wx-wx-wx. 3 vagrant vagrant 21 Feb 24 10:40 folder1
[vagrant@desktop1 ~]$ 

Nếu chúng tôi cố gắng xóa mà không đọc quyền thì thất bại:

[vagrant@desktop1 ~]$ rm -r folder1/
rm: cannot remove 'folder1/': Permission denied
[vagrant@desktop1 ~]$ sudo chmod +r folder1/
[vagrant@desktop1 ~]$ rm -r folder1/
[vagrant@desktop1 ~]$ 

Trong một bước tiến cho hai lần thử, sự khác biệt là nội dung thư mục không thể được đọc (getdents):

newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0333, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "folder1/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = -1 EACCES (Permission denied)
geteuid()                               = 1000
newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0333, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0
faccessat(AT_FDCWD, "folder1/", W_OK)   = 0
openat(AT_FDCWD, "folder1/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = -1 EACCES (Permission denied)
newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0333, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0

Với quyền đọc:

newfstatat(AT_FDCWD, "folder1/", {st_mode=S_IFDIR|0777, st_size=21, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "folder1/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFDIR|0777, st_size=21, ...}) = 0
fcntl(3, F_GETFL)                       = 0x38800 (flags O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_NOFOLLOW)
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents(3, /* 3 entries */, 32768)     = 80
close(3)                                = 0
geteuid()                               = 1000

Để kết luận ngay cả khi bạn sở hữu một thư mục và nó có bit thực thi, bạn vẫn cần quyền đọc để bạn có thể xem nội dung của nó và xóa thư mục. Nó không giống nhau cho một tập tin mặc dù.


0

Chà, tôi không đủ danh tiếng để nhận xét về câu trả lời của ttaran7, vì vậy có vẻ như đó là một câu trả lời. Phiếu bầu của tôi cũng không hiển thị công khai, do uy tín thấp. Tôi đã bỏ phiếu cho câu trả lời đó vì thực sự bao gồm cả dấu vết cuộc gọi hệ thống, thay vì chỉ là suy đoán.

Để trả lời câu hỏi của OP: Có, lý luận của bạn đã đúng: Bạn bị chặn khi không đọc được thư mục

Tôi đã chạy một dấu vết tương tự như những gì họ (ttaran7) đã làm vì tôi nghi ngờ lý do tương tự: Cuộc rmgọi sẽ thất bại khi không đọc được thư mục và đó sẽ là kết thúc, không có cơ hội để phàn nàn về việc thư mục bị trống. Khi nhìn lần thứ hai vào dấu vết mà tôi đã lấy, tôi nhận thấy rằng một cuộc gọi hệ thống đã được thực hiện để cố gắng hủy liên kết tên tệp được cung cấp bằng mọi cách:

newfstatat(AT_FDCWD, "folder1", {st_mode=S_IFDIR|0311, st_size=4096, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "folder1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = -1 EACCES (Permission denied)
openat(AT_FDCWD, "folder1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = -1 EACCES (Permission denied)
unlinkat(AT_FDCWD, "folder1", AT_REMOVEDIR) = -1 ENOTEMPTY (Directory not empty)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2995, ...}) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2995
read(3, "", 4096)                       = 0
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale/en_AU/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_AU/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=45256, ...}) = 0
mmap(NULL, 45256, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8db25ca000
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale- langpack/en/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=578, ...}) = 0
mmap(NULL, 578, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8db25c9000
close(3)                                = 0
write(2, "rm: ", 4rm: )                     = 4
write(2, "cannot remove 'folder1'", 23cannot remove 'folder1') = 23
openat(AT_FDCWD, "/usr/share/locale/en_AU/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale-langpack/en_AU/LC_MESSAGES/libc.mo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=2893, ...}) = 0
mmap(NULL, 2893, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8db25c8000
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": Permission denied", 19: Permission denied)     = 19
write(2, "\n", 1
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exitgroup(1)

Nhìn vào dòng thứ 4: unlinkat... thất bại vì thư mục KHÔNG trống. Bây giờ đó là những gì tôi sẽ xem xét hành vi bất ngờ, thực tế là nó cố gắng xóa thư mục, mặc dù không có quyền đọc.


Ah, bạn nói đúng, tôi sẽ sửa nó khi tôi đến một bàn phím thực sự. Cảm ơn.
ojklan
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.