Wed 10 Feb 2010 04:28:07 PM UTC, original submission:
Hello,
The remove(3) libc function fails to remove an empty directory.
Consider this program:
#v+
#include <stdio.h>
#include <error.h>
#include <errno.h>
int
main (int argc, char *argv[])
{
if (remove (argv[1]))
error (1, errno, "failed");
return 0;
}
#v-
Here's a comparison of Coreutils' `rm' and this program:
#v+
ludo@goober:~$ mkdir chbouib
ludo@goober:~$ rpctrace -o remove.log ./remove chbouib
./remove: failed: Operation not permitted
ludo@goober:~$ rpctrace -o rmdir.log rmdir chbouib
ludo@goober:~$ grep -C3 chbouib {remove,rmdir}.log
remove.log-task15378->vm_allocate (17147851 4096 1) = 0 16941056
remove.log-task15378->vm_deallocate (16936960 16) = 0
remove.log-task15378->mach_port_mod_refs (pn{ 8} 0 1) = 0
remove.log: 56->dir_unlink ("chbouib") = 0x40000001 (Operation not permitted)
remove.log-task15378->mach_port_deallocate (pn{ 8}) = 0
remove.log- 54->io_write_request ("./remove: " -1) = 0 10
remove.log- 54->io_write_request ("failed" -1) = 0 6
--
rmdir.log-task15343->vm_allocate (17147851 4096 1) = 0 16941056
rmdir.log-task15343->vm_deallocate (16936960 16) = 0
rmdir.log-task15343->mach_port_mod_refs (pn{ 8} 0 1) = 0
rmdir.log: 56->dir_rmdir ("chbouib") = 0
rmdir.log-task15343->mach_port_deallocate (pn{ 8}) = 0
rmdir.log-task15343->mach_port_deallocate (pn{ 5}) = 0
rmdir.log-task15343->mach_port_deallocate (pn{ 6}) = 0
#v-
My guess is that this is a problem in glibc:
#v+
int
remove (file)
const char *file;
{
/* First try to unlink since this is more frequently the necessary action. */
if (__unlink (file) != 0
/* If it is indeed a directory... */
&& (errno != EISDIR
/* ...try to remove it. */
|| __rmdir (file) != 0))
/* Cannot remove the object for whatever reason. */
return -1;
return 0;
}
#v-
Here glibc should be prepared to deal with `EPERM', which is the suitable error code for this case according to POSIX 2008. The "Rationale" section at http://www.opengroup.org/onlinepubs/9699919799/functions/unlink.html says that "[aA]pplications written for portability to both POSIX.1-2008 and the LSB should be prepared to handle either error code." Thus I think the right fix is to have glibc's remove(3) handle both `EISDIR' and `EPERM', regardless of the underlying kernel.
What do you think?
Thanks,
Ludo'.
|