Mail Archives: cygwin/2010/12/12/16:31:09
Matthias Andree wrote at 15:16 +0100 on Dec 12, 2010:
> This seems to be racey, the program below does not trigger the problem, so there
> must be something else that prevents unlink() from working properly, perhaps
> mandatory locks (possibly on the Windows side), or with (deeply) nested
> directories. I don't have time to extend the test case now to reproduce how
> "cygport" fails for me.
[...]
> /* DOES NOT SHOW THE PROBLEM AS-IS */
> /* test program cyg-rmdir.c, compile with:
> gcc -Wall -Wextra -O -o cyg-rmdir{,.c} -pedantic-errors -std=c89 */
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> #include <errno.h>
> #include <fcntl.h>
>
> static int fd = -1, f2 = -1;
>
> static void fail(const char *s) {
> perror(s);
> if (fd != -1) close(fd);
> if (f2 != -1) close(f2);
> (void)unlink("dir/file"); /* ignore failure */
> (void)rmdir("dir"); /* ignore failure */
> exit(EXIT_FAILURE);
> }
>
> static void child(void) {
> f2 = open("dir/file", O_RDONLY);
> if (f2 == -1) fail("child: open");
> sleep(3);
> close(f2);
> _exit(EXIT_SUCCESS);
> }
>
> int main(void) {
> if (mkdir("dir", 0755)) fail("mkdir");
> if ((fd = open("dir/file", O_CREAT|O_RDWR, 0644)) == -1) fail("open");
> if (write(fd, "test\n", 5) != 5) fail("write");
> if (fsync(fd)) fail("fsync");
> switch(fork()) {
> case 0: child(); _exit(EXIT_FAILURE); break;
> case -1: fail("fork");
> default: /* parent */ break;
> }
> sleep(1);
> if (unlink("dir/file")) fail("unlink");
> if (rmdir("dir")) fail("rmdir");
> if (close(fd)) fail("close");
> sleep(2);
> puts("success");
> return EXIT_SUCCESS;
> }
> /* END Of cyg-rmdir.c */
>
> --
> Matthias Andree
By the way, it's not unix vs. cygwin. NFS on unix has the same
issue. Have you ever seen those .nfs* files lying around?
cd /some/nfs/mount
mkdir dir
echo sleep 99 > dir/foo
sh dir/foo&
rm -rf dir
rm: dir: Directory not empty
ls -al dir
total 117
drwxr-xr-x 2 jhein jhein 3 Dec 12 09:10 ./
drwxrwxrwt 49 jhein jhein 1038 Dec 12 09:10 ../
-rw-r--r-- 1 jhein jhein 9 Dec 12 09:10 .nfs.67021bc0.ffff951e4.4
Furthermore, in your test, try changing to 'dir' and exec'ing some long
running process in the child. Then you should see the rmdir failure
until the child exits.
Here's your test program slightly modified (below). Invoke 'cyg-rmdir
fail' to see the rmdir fail (even though ls shows the dir empty).
Again, NFS will fail as well as cygwin.
Interestingly, if you don't cd before exec, the rmdir succeeds (in
cygwin). Invoke the new test as 'cyg-rmdir failnot'. NFS fails in
both cases. Only cygwin succeeds if you don't chdir(2) in first.
/* test program cyg-rmdir.c, compile with:
gcc -Wall -Wextra -O -o cyg-rmdir{,.c} -pedantic-errors -std=c89 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
static int fd = -1, failcase = 0;
static void fail(const char *s) {
perror(s);
(void)unlink("dir/file"); /* ignore failure */
(void)rmdir("dir"); /* ignore failure */
exit(EXIT_FAILURE);
}
static void child(void) {
if (failcase == 0) {
/* this does not make the rmdir in the parent fail */
execl("dir/file", "file", NULL);
fail("exec failed");
}
/* chdir + exec makes the rmdir in the parent fail */
if (chdir("dir") != 0) fail("chdir");
execl("./file", "file", NULL);
fail("exec failed");
}
int main(int argc, char **argv) {
char *prog="#!/bin/sh\nsleep 10\n";
int len = strlen(prog);
if (argc > 1 && strcmp(argv[1], "fail")==0)
failcase = 1;
if (mkdir("dir", 0755)) fail("mkdir");
if ((fd = open("dir/file", O_CREAT|O_RDWR, 0755)) == -1) fail("open");
if (write(fd, prog, len) != len) fail("write");
if (close(fd)) fail("close");
system("set -x;cat dir/file;ls -al dir");
switch(fork()) {
case 0: child(); _exit(EXIT_FAILURE); break;
case -1: fail("fork");
default: /* parent */ break;
}
sleep(1);
system("set -x;echo before unlinks;ls -al . dir");
if (unlink("dir/file")) fail("unlink");
system("set -x;ls -al . dir");
if (rmdir("dir")) fail("rmdir");
sleep(2);
puts("success");
return EXIT_SUCCESS;
}
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
- Raw text -