[comp.sys.ibm.pc] Possible bug in MS-DOS 3.1 regarding file locking around spawnl

rha@bunker.UUCP (Robert H. Averack) (04/27/88)

     I have encountered what I believe is a bug in MS-DOS Version 3.1,
regarding the preservation of file locks.  Basically, what is involved
can be described by the following pseudo-code:

	while true
	{
		open a file;
		...
		read and lock a record;
		...
		SPAWN a subprogram;
		...
		update a previously read and locked record;
		unlock the recently updated record;
		...
		close a previously opened file;
	}

     In a nutshell, what is happening is that the spawnl(P_WAIT,...) makes
the currently open files "available" to the subprogram, and the ultimate
exit from the subprogram attempts to close all open file handles.  What,
in fact, happens is that the files remain available to the parent program
upon its regaining of control.  However, all previously existing locks on
those files are removed.  Therefore, the attempt to unlock the previously
locked record fails.  More critically, the records can unwittingly be
modified by another task, if in fact, the files in question are being
shared (why else would we do locking? ;-) ).

     I am including an example of code and trace at the end of this posting
so you may try it for yourself.  As you will see, I can "re-establish" the
file locks at the original locations, after the spawnl(), which I suppose
is the "work-around".

     My real question is:  IS THIS A BUG OR A FEATURE OF MS-DOS?

     Thanks for any help!

BTW - In case you were wondering, I've produced the same problem, whether
using locking() in C or System Call 0x5C (again, no surprise, I figure).


=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=

	C O D E   E X A M P L E   S T A R T S   H E R E   . . .

=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=


#include <sys\locking.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#include <stdio.h>

main()
{
	int do_lock();
	int lockstat;
	int i;
	int fd[5];
	char fname[8];
	char buf[81];

	/* open and display some contents from each test file */
	buf[80] = '\0';
	for (i = 0 ; i < 5 ; ++i)
	{
		sprintf(fname, "file%d", i+1);
		if ( (fd[i] = open(fname, O_RDWR)) < 0 )
			fprintf(stdout, "Failed to open %s\n", fname);
		else
		{
			read(fd[i], buf, 80);
			fprintf(stdout, "\nI just read 80 bytes from fd=%d ... they are ...\n%s\n", fd[i], buf);
		}
	}

	/* lock one byte in each test file */
	fprintf(stdout, "\n\n");
	for (i = 0 ; i < 5 ; ++i)
	{
		if (fd[i] >= 0)
		{
			if ( (lockstat = do_lock(fd[i], 0x40000000L, 1L, 1)) == 0 )
				fprintf(stdout, "Successful lock on fd[%d]=%d\n", i, fd[i]);
			else
			{
				if (lockstat < 0)
					fprintf(stdout, "Lock failed on fd[%d]=%d\n", i, fd[i]);
				else
					fprintf(stdout, "Lseek failed on fd[%d]=%d\n", i, fd[i]);
			}
		}
	}

	/* spawn a subprogram (all it does is "exit(0)") */
	fprintf(stdout, "\n\nABOUT TO EXECUTE SPAWNL ...\n");
	spawnl(P_WAIT, "nop.exe", "nop", (char *)0);
	fprintf(stdout, "RETURNED FROM SPAWNL ...\n\n");

	/* display some more stuff from each test file */
	for (i = 0 ; i < 5 ; ++i)
	{
		if (fd[i] >= 0)
		{
			read(fd[i], buf, 80);
			fprintf(stdout, "\nI just read 80 bytes from fd=%d ... they are ...\n%s\n", fd[i], buf);
		}
	}

	/* try to unlock what was previously locked in each test file */
	fprintf(stdout, "\n\n");
	for (i = 0 ; i < 5 ; ++i)
	{
		if (fd[i] >= 0)
		{
			if ( (lockstat = do_lock(fd[i], 0x40000000L, 1L, 0)) == 0 )
				fprintf(stdout, "Successful unlock on fd[%d]=%d\n", i, fd[i]);
			else
			{
				if (lockstat < 0)
					fprintf(stdout, "Unlock failed on fd[%d]=%d\n", i, fd[i]);
				else
					fprintf(stdout, "Lseek failed on fd[%d]=%d\n", i, fd[i]);
			}
		}
	}

	/* reestablish the lost locks in each test file */
	fprintf(stdout, "\n\nRE-ESTABLISHING LOST LOCKS ...\n");
	for (i = 0 ; i < 5 ; ++i)
	{
		if (fd[i] >= 0)
		{
			if ( (lockstat = do_lock(fd[i], 0x40000000L, 1L, 1)) == 0 )
				fprintf(stdout, "Successful lock on fd[%d]=%d\n", i, fd[i]);
			else
			{
				if (lockstat < 0)
					fprintf(stdout, "Lock failed on fd[%d]=%d\n", i, fd[i]);
				else
					fprintf(stdout, "Lseek failed on fd[%d]=%d\n", i, fd[i]);
			}
		}
	}

	/* now try to unlock what was previously locked in each test file */
	fprintf(stdout, "\n");
	for (i = 0 ; i < 5 ; ++i)
	{
		if (fd[i] >= 0)
		{
			if ( (lockstat = do_lock(fd[i], 0x40000000L, 1L, 0)) == 0 )
				fprintf(stdout, "Successful unlock on fd[%d]=%d\n", i, fd[i]);
			else
			{
				if (lockstat < 0)
					fprintf(stdout, "Unlock failed on fd[%d]=%d\n", i, fd[i]);
				else
					fprintf(stdout, "Lseek failed on fd[%d]=%d\n", i, fd[i]);
			}
		}
	}

	exit(0);
}

do_lock(fd, off, len, act)
int fd;
long off;
long len;
int act;
{
	long curloc;
	int status;

	/* save the current file pointer and point to the lock offset */
	if ( (curloc=lseek(fd,0L,SEEK_CUR)) == -1L )
		return(1);
	if (lseek(fd,off,SEEK_SET) == -1L)
		return(1);

	/* either lock or unlock the specified number of bytes */
	if (act)
	{
		fprintf(stdout, "*** Someone wants me to lock %ld bytes starting at %lx in fd=%d  ***\n", len, off, fd);
		status = locking(fd,LK_LOCK,len);
	}
	else
	{
		fprintf(stdout, "***  Someone wants me to unlock %ld bytes starting at %lx in fd=%d  ***\n", len, off, fd);
		status = locking(fd,LK_UNLCK,len);
	}

	/* reset the file pointer and return the lock status */
	if (lseek(fd,curloc,SEEK_SET) == -1L)
		return(1);
	else
		return(status);
}


=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=

	T R A C E   E X A M P L E   S T A R T S   H E R E   . . .

=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=



I just read 80 bytes from fd=5 ... they are ...
#include <sys\locking.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>.h>

I just read 80 bytes from fd=6 ... they are ...
#include <sys\locking.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>.h>

I just read 80 bytes from fd=7 ... they are ...
#include <sys\locking.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>.h>

I just read 80 bytes from fd=8 ... they are ...
#include <sys\locking.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>.h>

I just read 80 bytes from fd=9 ... they are ...
#include <sys\locking.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>.h>


*** Someone wants me to lock 1 bytes starting at 40000000 in fd=5  ***
Successful lock on fd[0]=5
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=6  ***
Successful lock on fd[1]=6
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=7  ***
Successful lock on fd[2]=7
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=8  ***
Successful lock on fd[3]=8
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=9  ***
Successful lock on fd[4]=9


ABOUT TO EXECUTE SPAWNL ...
RETURNED FROM SPAWNL ...


I just read 80 bytes from fd=5 ... they are ...

#include <process.h>
#include <stdio.h>

main()
{
	int do_lock();
	int locnt loc

I just read 80 bytes from fd=6 ... they are ...

#include <process.h>
#include <stdio.h>

main()
{
	int do_lock();
	int locnt loc

I just read 80 bytes from fd=7 ... they are ...

#include <process.h>
#include <stdio.h>

main()
{
	int do_lock();
	int locnt loc

I just read 80 bytes from fd=8 ... they are ...

#include <process.h>
#include <stdio.h>

main()
{
	int do_lock();
	int locnt loc

I just read 80 bytes from fd=9 ... they are ...

#include <process.h>
#include <stdio.h>

main()
{
	int do_lock();
	int locnt loc


***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=5  ***
Unlock failed on fd[0]=5
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=6  ***
Unlock failed on fd[1]=6
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=7  ***
Unlock failed on fd[2]=7
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=8  ***
Unlock failed on fd[3]=8
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=9  ***
Unlock failed on fd[4]=9


RE-ESTABLISHING LOST LOCKS ...
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=5  ***
Successful lock on fd[0]=5
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=6  ***
Successful lock on fd[1]=6
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=7  ***
Successful lock on fd[2]=7
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=8  ***
Successful lock on fd[3]=8
*** Someone wants me to lock 1 bytes starting at 40000000 in fd=9  ***
Successful lock on fd[4]=9

***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=5  ***
Successful unlock on fd[0]=5
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=6  ***
Successful unlock on fd[1]=6
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=7  ***
Successful unlock on fd[2]=7
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=8  ***
Successful unlock on fd[3]=8
***  Someone wants me to unlock 1 bytes starting at 40000000 in fd=9  ***
Successful unlock on fd[4]=9


=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=

	T R A C E   E X A M P L E   E N D S   H E R E   . . .

=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=.=


-- 
                       {yale!,decvax!,philabs!}bunker!rha                    
                                  Bob Averack                           
                        Bunker Ramo, an Olivetti Company                      
               Two Enterprise Drive - Shelton, Connecticut 06484             

rha@bunker.UUCP (Robert H. Averack) (04/27/88)

Hello again!  In article <3497@bunker.UUCP> I wrote:

>     I have encountered what I believe is a bug in MS-DOS Version 3.1,
>regarding the preservation of file locks. 
			.....
>     In a nutshell, what is happening is that [upon return from]
>spawnl(P_WAIT,...) all previously existing locks on files are removed.
			.....
>     My real question is:  IS THIS A BUG OR A FEATURE OF MS-DOS?

     Hot off the presses...I just ran my test program on an MS-DOS 3.20
installation.  THE LOCKS ARE PRESERVED following the spawnl()!

     So, since 3.1 and 3.2 behave differently regarding this action, I
think that we can conclude that it is a BUG in MS-DOS 3.1.

     Now, can anybody tell me if this problem exists in 3.3...I wouldn't
put anything past Microsoft 8-) !

     Thanks again!

-- 
                       {yale!,decvax!,philabs!}bunker!rha                    
                                  Bob Averack                           
                        Bunker Ramo, an Olivetti Company                      
               Two Enterprise Drive - Shelton, Connecticut 06484