Dear reader,

CVS 1.10.* client sometimes has problems to prune directories on NT shares with 
enabled OPLOCKS. Mind that this problems only reveil themselves when using the 
MicroSoft Visual Studio Libraries. The cvs 1.10.0 and 1.10.5 clients that can be 
downloaded suffer from the problem.

Assume an empty module called "empty". The command "cvs update -r HEAD -P -d empty" 
will fail when it is run on a share. It cannot unlink the empty/CVS/Tag file. When cvs 
tries to unlink this file in de deep_remove_dir() subroutine it gets a EACCESS errno. 
Due to some hacks in the code it sadly assumes the object to be a directory [this is a 
bug]. However, in the end the error message yields something like: "directory not 
empty", which is convenient enough.

The little C-program listed below illustrates the essential actions cvs runs on the 
CVSADM_TAG file. Create it, call chmod and unlink. In this little program the unlink 
will repeatably fail on a NT share with opportunistic locks enabled. The errno code 
will be 13 (EACCESS). Some trial-and-error coding reveiled that a work-around could be 
to open and close the file for "a+" just before unlinking. 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

main()
{
        int r;
        extern int errno;
        FILE *fp;

        fp = fopen("Tag", "w+");
        fprintf(fp, "\n");
        fclose(fp);

        chmod("Tag", _S_IWRITE);

        errno = 0;
        r = unlink("Tag");
        printf("Unlink Tag returned: %d (errno == %d)\n", r, errno);
}

A context patch in src/filesubr.c could be something like the following (starting from 
the strcmp).

/* Win32 unlink is stupid - it fails if the file is read-only */
chmod (buf, _S_IWRITE);

/* NT may use OPLOCKS. These impose problems on the CVSADM_TAG file. */
/* The latest exclusive lock is gained by the chmod() call above. */
/* Opening a file for "a+" and write some data to it demotes the lock. */
if (strcmp (dp->d_name, "Tag") == 0) {
        FILE *fp = fopen(buf, "a+");
        if (fp != NULL) {
                fprintf(fp, "\n");
                fclose(fp);
        }
}

if (unlink (buf) != 0 )

This is clearly not code that should be in a production version but the work-around 
does what it has to do.

Kind regards,

Xirion bv
Frank Streur

Reply via email to