1

Suppose c.txt is in directory b. unlink c.txt is easy, the system just removes entry {XXX, c.txt} in directory b. But what happens if b is a subdirectory of a, and I want to unlink b, is the procedure the same or more complicated?

mvp
  • 111,019
  • 13
  • 122
  • 148
stonestrong
  • 337
  • 1
  • 5
  • 13

3 Answers3

5

unlink(2) can only delete a file, while rmdir(2) can only delete empty directory.

If you want to delete directory recursively, you must use both syscalls intelligently. You may find many different implementations of recursive delete, for example this one is using nftw, or this one is using opendir/readdir.

Community
  • 1
  • 1
mvp
  • 111,019
  • 13
  • 122
  • 148
  • suppose we have "a/b/c", and there is another "d/e" where e is a hard link of c, if we remove directory a and its subcontent, then where does e points to, invalid? – stonestrong Mar 11 '13 at 13:04
  • I refered to `Principles of Computer System Design`,in this condition, e ends up as a dangling reference which is not disruptive. – stonestrong Mar 11 '13 at 13:34
  • 3
    @stonestrong If it is a /symbolic/ link, it'll end up as a dangling reference, but a /hardlink/ will cause the file to still have a use count of 1, so there file is still there. You can try this yourself with: `mkdir -p a/b ; echo Hello, World\! > a/b/c ; mkdir d ; ln -s ../a/b/c d/e ; ln a/b/c d/f ; rm -rf a ; cat d/e ; cat d/f` – RolKau Nov 13 '13 at 13:04
1

From man page for unlink:

When the utility is called as unlink, only one argument, 
which must not be a directory, may be supplied.  

So when using unlink, you cannot pass directory as a parameter.

kamituel
  • 34,606
  • 6
  • 81
  • 98
  • when talking about why Unix file system allows only links to files, not to directories, `Principles of Computer System Design` give an example of unlink a directory, it's on Page 100. If the example is not appropriate, is there any better explanation? – stonestrong Mar 11 '13 at 13:11
0

On Linux it seems the result is EISDIR, however on OSX the result seems to be EPERM, so apparently you can't safely call unlink() on something and then try it as a directory only if unlink() fails.

dickbutt:~/unlink$ uname -a
Linux dickbutt 4.14.69-0-vanilla #1-Alpine SMP Mon Sep 10 19:33:23 UTC 2018 x86_64 Linux
dickbutt:~/unlink$ cat ./unlink.c
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main() {
    int ret = unlink("./xxx");
    printf("ret is [%d] and errno is [%d] aka [%s]\n", ret, errno,
strerror(errno));
}
dickbutt:~/unlink$ mkdir xxx
dickbutt:~/unlink$ gcc ./unlink.c
dickbutt:~/unlink$ ./a.out
ret is [-1] and errno is [21] aka [Is a directory]
dickbutt:~/unlink$
notgay:unlink user$ uname -a
Darwin notgay.local 14.5.0 Darwin Kernel Version 14.5.0: Sun Jun  4 21:40:08 PDT 2017; root:xnu-2782.70.3~1/RELEASE_X86_64 x86_64
notgay:unlink user$ cat ./unlink.c
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main() {
    int ret = unlink("./xxx");
    printf("ret is [%d] and errno is [%d] aka [%s]\n", ret, errno, strerror(errno));
}
notgay:unlink user$ mkdir xxx
notgay:unlink user$ gcc ./unlink.c
notgay:unlink user$ ./a.out
ret is [-1] and errno is [1] aka [Operation not permitted]
notgay:unlink user$