ทำไม“ rm -r” ไม่สามารถลบโฟลเดอร์นี้ได้?


12

ฉันมีโฟลเดอร์ที่มี-wxสิทธิ์เรียกว่าfolder1และอีกโฟลเดอร์หนึ่งเรียกว่าfolder2มีrwxสิทธิ์

ฉันพยายามลบfolder1โดยใช้คำสั่งนี้:

rm -r folder1

แต่ฉันได้รับข้อผิดพลาดต่อไปนี้:

rm: cannot remove 'folder1': Permission denied

เหตุผลที่ฉันคิดว่าฉันได้รับข้อผิดพลาดนี้เนื่องจากrmโปรแกรมจำเป็นต้องได้รับเนื้อหาของfolder1(รับชื่อของไฟล์และโฟลเดอร์ที่อยู่ภายในfolder1) เพื่อที่จะสามารถลบเนื้อหานั้น (เพราะคุณไม่สามารถลบไฟล์ได้ หรือโฟลเดอร์โดยไม่ทราบชื่อฉันคิดว่า) จากนั้นrmโปรแกรมสามารถลบfolder1ตัวเอง

แต่เนื่องจากfolder1ไม่มีreadสิทธิ์rmโปรแกรมจึงไม่สามารถรับเนื้อหาได้ดังนั้นจึงไม่สามารถลบเนื้อหาและเนื่องจากไม่สามารถลบเนื้อหาได้จึงไม่สามารถลบเนื้อหาได้

ฉันถูกไหม?


1
ทำ "ls -l" แล้วบอกเราว่าสิทธิ์ของ DIRECTORY นั้นคืออะไร
jamesqf

คำตอบ:


19

ฉันคิดว่าการวิเคราะห์ของคุณถูกต้อง: คุณไม่สามารถลบไดเรกทอรีได้เนื่องจากมันไม่ว่างเปล่าและคุณไม่สามารถลบมันได้เนื่องจากคุณไม่เห็นเนื้อหา

ฉันแค่ลองทำดู:

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

เมื่อฉันเขียนคำว่า“ คุณ” ฉันหมายถึงโปรแกรมใด ๆ ที่คุณสามารถเรียกใช้ได้ rm -rคำสั่งของคุณจะเห็นว่าfolder1เป็นไดเรกทอรีดังนั้นจึงพยายามค้นหาเนื้อหาเพื่อล้างมัน แต่ล้มเหลวเนื่องจากไม่มีสิทธิ์การอ่านจากนั้นจึงพยายามลบ แต่ล้มเหลวเนื่องจากไม่ว่างเปล่า “ การอนุญาตที่ถูกปฏิเสธ” กำลังทำให้เข้าใจผิด ฉันคิดว่า "ไดเรกทอรีไม่ว่างเปล่า" (เช่นrmdirรายงาน) จะเหมาะสมกว่า)


4
ไม่สามารถรายงานได้Directory not emptyในกรณีนี้เนื่องจากจะไม่ทราบว่าว่างเปล่าหรือไม่ คุณจะยังคงได้รับข้อผิดพลาดเดียวกันเมื่อพยายามลบไดเรกทอรีว่างเปล่าที่คุณไม่ได้รับอนุญาตให้อ่าน (นอกจากนี้โปรดเพิกเฉยความคิดเห็นก่อนหน้าของฉันฉันไม่ได้ใส่ความคิดของฉันไว้)
Kusalananda

1
@ Kusalananda ฟังดูมีเหตุผล แต่rmdirสามารถรายงาน“ ไดเรกทอรีไม่ว่างเปล่า” และถ้าคุณอ่านการทดสอบของฉันคุณจะเห็นว่ามันยอมรับการลบfolder1ไดเรกทอรีโดยไม่ได้รับอนุญาตให้อ่านเมื่อฉันได้ทำการลบมันแล้ว
2233709

2
การทดสอบของคุณแสดงให้เห็นถึงความแตกต่างที่น่าสนใจระหว่างระบบของเรา ฉันPermission deniedพยายามrm -r folder1เมื่อมันว่างเปล่า ฉันใช้ OpenBSD ไม่ใช่ Linux
Kusalananda

@ Kusalananda นั่นน่าสนใจ ฉันจะคิดว่าพฤติกรรมนี้ถูกระบุโดยสเปคของ Unix เดี่ยวเพื่อให้ Linux และ {ฟรี, สุทธิ, เปิด} BSD จะทำงานเหมือนกัน (สำหรับบันทึกฉันใช้ Debian Stretch 9.8 กับ linux 4.9.144-3 x86_64 เคอร์เนล)
user2233709

อืม ... สิ่งเดียวที่ POSIX กล่าวคือว่าถ้าตัวถูกดำเนินการเป็นไดเรกทอรีและ-rจะใช้รายการแต่ละ directory (ยกเว้น.และ..) rm -rควรจะออกราวกับว่าพวกเขาเป็นตัวถูกดำเนินการแฟ้ม ดูเหมือนว่า GNU rmจะทำเพียงแค่rmdir()ในไดเรกทอรีถ้ามันไม่สามารถอ่านได้เพราะมันจะไม่มีวิธีรับเนื้อหาของมัน
Kusalananda

7

เพื่อให้การลบเกิดขึ้นระบบจะต้องสามารถอ่านเนื้อหาและระบุสิ่งที่จะต้องถูกลบ

ฉันลองจำลองสิ่งที่คุณพยายาม:

[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 ~]$ 

หากเราลองลบโดยไม่ได้รับอนุญาตอ่านมันล้มเหลว:

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

ใน strace สำหรับสองครั้งความแตกต่างคือเนื้อหาไดเรกทอรีไม่สามารถอ่านได้ (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

ด้วยสิทธิ์การอ่าน:

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

ในการสรุปแม้ว่าคุณจะเป็นเจ้าของไดเรกทอรีและมีบิตที่สามารถเรียกใช้งานได้คุณยังต้องมีสิทธิ์อ่านเพื่อให้คุณสามารถดูเนื้อหาและลบโฟลเดอร์ได้ มันไม่เหมือนกันสำหรับไฟล์


0

ฉันไม่มีชื่อเสียงพอที่จะให้ความเห็นเกี่ยวกับคำตอบของ ttaran7 ดังนั้นมันจึงดูเหมือนว่าจะต้องเป็นคำตอบ การโหวตของฉันไม่ปรากฏต่อสาธารณะเนื่องจากชื่อเสียงที่ต่ำ ฉันลงคะแนนว่าคำตอบนั้นรวมถึงการติดตามการโทรของระบบมากกว่าการเก็งกำไร

เพื่อตอบคำถามของ OP: ใช่เหตุผลของคุณถูกต้อง: คุณถูกบล็อกเมื่อไม่สามารถอ่านไดเรกทอรี

ฉันวิ่งตามรอยคล้ายกับสิ่งที่พวกเขา (ttaran7) ทำเพราะฉันสงสัยว่ามีเหตุผลแบบเดียวกัน: การrmโทรจะล้มเหลวเมื่อล้มเหลวในการอ่านไดเรกทอรีและนั่นจะเป็นจุดสิ้นสุดของเรื่องนั้นไม่มีโอกาสบ่นเกี่ยวกับไดเรกทอรีที่ว่างเปล่า เมื่อดูที่การติดตามครั้งที่สองฉันสังเกตเห็นว่ามีการเรียกใช้ระบบเพื่อพยายามยกเลิกการเชื่อมโยงชื่อไฟล์ที่ให้ไว้ต่อไป:

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)

ดูบรรทัดที่ 4: unlinkat... ซึ่งล้มเหลวเนื่องจากไดเรกทอรีไม่ว่างเปล่า ตอนนี้เป็นสิ่งที่ฉันจะพิจารณาพฤติกรรมที่ไม่คาดคิดความจริงก็พยายามลบไดเรกทอรีเลยแม้ว่าจะไม่มีสิทธิ์อ่านนั่นคือ


อ่าคุณพูดถูกฉันจะแก้ไขให้ถูกต้องเมื่อฉันไปถึงแป้นพิมพ์จริง ขอบคุณ
ojklan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.