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

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,T_TO_NO_BRKTS_FREEMAIL
X-Spam-Check-By: sourceware.org
Message-ID: <4D04D92F.6000002@gmx.de>
Date: Sun, 12 Dec 2010 15:16:15 +0100
From: Matthias Andree <matthias DOT andree AT gmx DOT de>
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.13) Gecko/20101207 Lightning/1.0b2 Thunderbird/3.1.7
MIME-Version: 1.0
To: cygwin AT cygwin DOT com
Subject: Re: 1.7.7: rm -rf sometimes fails - race condition?
References: <4D026815 DOT 4070606 AT gmx DOT de> <20101210182652 DOT GA27615 AT ednor DOT casa DOT cgf DOT cx> <3D3D7FA2B44B477A8342F96F72AE1BE7 AT multiplay DOT co DOT uk> <20101212124248 DOT GB11357 AT calimero DOT vinschen DOT de>
In-Reply-To: <20101212124248.GB11357@calimero.vinschen.de>
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.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

Am 12.12.2010 13:42, schrieb Corinna Vinschen:

> So, what cygwin tries to do in the first place is to move files in use
> into the recycle bin.  However, on Windows you need DELETE access rights
> to be able to do so.  And, this doesn't work for remote drives.  On
> remote drives we can only try to rename the file to some temporary
> filename and hope for the best.  Afterwards Cygwin sets the delete
> dispostion flag and returns success if setting the dispostion flag
> succeeded.  After all, that's the maximum possible on Windows, and for
> all we can tell the file has been deleted.  The fact that the directory
> entry lingers until the last handle to the file has been closed is
> something Cygwin has no control over.

Well, there's the problem.

1. Assume you have this tree:

dir/
dir/file1
dir/file2

2. Assume that dir/file2 is in use.

3. Assume you have sufficient rights and run: rm -rf dir

Cygwin deletes file1, sets the delete disposition for file2, and unlink("file2")
returns before the file is really gone.

rm.exe believes the directory is empty because it deleted all files
successfully.  HOWEVER when rm then runs rmdir("dir"), that fails, because
Cygwin does not mask the Windows artifact that the file removal is deferred.

There is a mismatch between what Cygwin reported to the application (last file
successfully removed) and what is actually there.

Now rm -rf gets rmdir("dir") == -1 with errno == ENOTEMPTY.  This rmdir()
failure is bogus.

Now I think that rmdir() needs to jump through the same hoops as unlink(), only
it is even more complex because Cygwin needs to track or check if all files
(including sub-directories) in a directory have been unlink()ed and rmdir()ed

I think that rmdir() must not fail with ENOTEMPTY or EEXIST if all files have
been successfully removed.


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.

Is there a chance that Cygwin's rmdir() might be extended to ensure this? I
mean, in a not-too-distant 1.7.X release?

/* 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

--
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