delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2010/12/12/16:31:09

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW,TW_RW,TW_WX,TW_XR
X-Spam-Check-By: sourceware.org
Message-ID: <14729-1292189455-742299@sneakemail.com>
Date: Sun, 12 Dec 2010 14:30:48 -0700
MIME-Version: 1.0
From: "John Hein" <j8raa6t5a9 AT snkmail DOT com>
To: cygwin AT cygwin DOT com
To: "matthias.andree at gmx.de" <wfs9czf2xt AT sneakemail DOT com>
To: "jhein at symmetricom.com" <45ezpuk55t AT sneakemail DOT com>
In-Reply-To: <4D04D92F.6000002@gmx.de>
References: <4D04D92F DOT 6000002 AT gmx DOT de>
Subject: Re: 1.7.7: rm -rf sometimes fails - race condition?
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Unsubscribe: <mailto:cygwin-unsubscribe-archive-cygwin=delorie DOT com AT cygwin DOT com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019