Created attachment 185149 [details] patch for the unlink(2) man page update unlink(2) manpage states both EISDIR and EPERM are returned if the user attempts to remove a directory. unlink(2) function calls kern_unlinkat(), which does not return EISDIR in any case. [1] Also, POSIX standard states that EPERM should be returned when unlinking a directory and EISDIR is only used by Linux Standard Base (LSB).[1] As the proof of concept, the code below shows only EPERM is returned while attempting to unlink a directory; ~/code/test/unlink_test % ls -l total 40 drwxr-xr-x 2 fnoyanisi fnoyanisi 512 Aug 8 22:00 dummy/ -rwxr-xr-x 1 fnoyanisi fnoyanisi 9135 Aug 8 22:03 unlink_test* -rw-r--r-- 1 fnoyanisi fnoyanisi 222 Aug 8 22:25 unlink_test.c ~/code/test/unlink_test % cat unlink_test.c #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> int main(int argc, char **argv){ if (unlinkat(argv[1])!=0) printf("Error %d : %s\n",errno, strerror(errno)); return 0; } ~/code/test/unlink_test % ./unlink_test dummy Error 1 : Operation not permitted ~/code/test/unlink_test % With the attached patch file, the line which is in the ERRORS section and states that [EISDIR] is returned by unlink(2) when unlinking a directory is removed from the manual page. unlink.2.fni -> working copy unlink.2 -> unlink(2) manpage from revision 321776 Diff file was generated with the command below diff -u unlink.2 unlink.2.fni > unlink.2.diff Subversion revision details for the original unlink(2) manpage /usr/src % svn info Path: . Working Copy Root Path: /usr/src URL: svn://svn.freebsd.org/base/release/11.1.0 Relative URL: ^/release/11.1.0 Repository Root: svn://svn.freebsd.org/base Repository UUID: ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f Revision: 321776 Node Kind: directory Schedule: normal Last Changed Author: gjb Last Changed Rev: 321354 Last Changed Date: 2017-07-22 08:55:38 +1200 (Sat, 22 Jul 2017) [1] https://svnweb.freebsd.org/base/release/11.0.1/sys/kern/vfs_syscalls.c?revision=306421&view=markup#l1728 [2] http://pubs.opengroup.org/onlinepubs/9699919799/
There was a case that unlink(2) may return EISDIR. Function kern_unlinkat calls namei(9) to find the parent directory of the file; it will return EISDIR if the requested path was '/'. Since '/' isn't a real link (but '/.' and '/..'), it can't be unlinked anyways. Test: # cat unlink.c #include <unistd.h> #include <stdio.h> int main(int argc, char **argv) { if(argc != 2) { fprintf(stderr, "Usage: %s <path>\n", argv[0]); return -1; } if(unlink(argv[1]) < 0) { perror(argv[1]); return 1; } return 0; } # gcc -Wall -O1 unlink.c -o unlink # ./unlink /etc/ /etc/: Operation not permitted # ./unlink /. /.: Operation not permitted # ./unlink / /: Is a directory
This has been fixed a while ago.