[comp.sys.amiga.tech] File copy routine screwing up big-time. Any ideas?

peter@sugar.uu.net (Peter da Silva) (11/26/88)

The following code does truly horrible things when I run it in a subdirectory
of RAD: (and maybe elsewhere, but I've only found a problem in RAD:s). The
somewhat odd sequence of file opening and closing is to minimise the disk
swaps in a one-drive system... for a file small enough to fit in the buffer
only one disk swap is needed, for example.

Anyway, there may be nothing wrong with this code, in which case I may have
found a bug in RAD:.

It will do things like creating a loop in the directory, the original file
will vanish, and the copy will not show up.

If I run it often enough it blows away RAD:, but VD0: is copacetic.

------- snip snip -------

#include <exec/memory.h>
#include <libraries/dos.h>

void *AllocMem();

#include <stdio.h>

#define COPYBUF 32768
FILE *debug = 0;

/* Quick kludge main() to kick the code off */

main(ac, av)
int ac;
char **av;
{
	if(av[1][0] == '-' && av[1][1] == 'd') {
		debug = stderr;
		av++;
		ac--;
	}

	if(ac < 3) {
		TellUser("Not enough arguments", 0, 0);
		exit(20);
	}
	CopyNamed(av[1], av[2]);
}

/* Copy a single named file. */

CopyNamed(from, to)
char *from, *to;
{
	long Inlock;
	struct FileInfoBlock *fib;

	long Infile, Outfile;
	char *buffer;
	long bufsiz;
	long nwrite, nread;
	int ioerr;

	/* Get file info block, for file protection and comment */
	if(!(Inlock = Lock(from, MODE_OLDFILE))) {
		TellUser("Can't Lock", from, IoErr());
		return 0;
	}

	if(!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC))) {
		OutOfMemory(from);
		UnLock(Inlock);
		return 0;
	}

	if(!Examine(Inlock, fib)) {
		TellUser("Can't Examine", from, IoErr());
		FreeMem(fib, sizeof(struct FileInfoBlock));
		UnLock(Inlock);
		return 0;
	}
	UnLock(Inlock);

	/* Allocate a moderately large buffer. */
	for(bufsiz = COPYBUF; bufsiz >= 512; bufsiz /= 2)
		if(buffer = AllocMem(bufsiz, MEMF_PUBLIC))
			break;

	if(bufsiz < 512) {
		OutOfMemory(from);
		FreeMem(fib, sizeof(struct FileInfoBlock));
		return 0;
	}

	if(debug)
		fprintf(debug, "About to open '%s' for reading.\n", from);

	/* Open input file, read blocks from it, and close it as soon
	   as a partial read is made... this will keep us from having
	   to go back to the original disk if there's no more data */

	if(!(Infile = Open(from, MODE_OLDFILE))) {
		TellUser("Can't Open", from, IoErr());
		FreeMem(buffer, bufsiz);
		FreeMem(fib, sizeof(struct FileInfoBlock));
		return 0;
	}

	if(debug)
		fprintf(debug, "About to enter main loop, copying '%s' to '%s'\n",
			from, to);
	nread = Read(Infile, buffer, bufsiz);
	if(nread < 0) ioerr = IoErr();
	if(nread >= 0) {
		if(nread < bufsiz) {
			Close(Infile);
			Infile = 0;
		}

		if(debug)
			fprintf(debug, "About to open '%s' for writing.\n", to);

		/* Held off opening output file until I'm about to write to it.
		   this, again, will reduce disk swaps */
		if(!(Outfile = Open(to, MODE_NEWFILE))) {
			TellUser("Can't Create", to, IoErr());
			FreeMem(buffer, bufsiz);
			if(Infile) Close(Infile);
			FreeMem(fib, sizeof(struct FileInfoBlock));
			return 0;
		}

		do {
			if(Infile && nread < bufsiz) {
				Close(Infile);
				Infile = 0;
			}
			nwrite = Write(Outfile, buffer, nread);
			fprintf(debug, "read %d wrote %d\n", nread, nwrite);
			if(nwrite < nread) ioerr = IoErr();
		} while(
			Infile &&
			nwrite == nread &&
			(nread = Read(Infile, buffer, bufsiz)) > 0 );
		if(nread < 0)
			ioerr = IoErr();

		if(debug)
			fprintf(debug, "Finished, about to close files.\n");
		Close(Outfile);
	}

	/* This will only happen on a write error */
	if(Infile) Close(Infile);
	FreeMem(buffer, bufsiz);

	if(nread < 0) {
		TellUser("Read error", from, ioerr);
		FreeMem(fib, sizeof(struct FileInfoBlock));
		return 0;
	}
	if(nwrite < nread) {
		TellUser("Write error", from, ioerr);
		FreeMem(fib, sizeof(struct FileInfoBlock));
		return 0;
	}

	SetComment(to, fib->fib_Comment);
	SetProtection(to, fib->fib_Protection);
	FreeMem(fib, sizeof(struct FileInfoBlock));
	if(debug)
		fprintf(debug, "Copy successful, returning.\n");
	return 1;
}

TellUser(msg, file, ioerr)
char *msg, *file;
int ioerr;
{
	fprintf(stderr, "CopyTest");
	if(file) fprintf(stderr, ": %s", file);
	fprintf(stderr, ": %s", msg);
	if(ioerr) fprintf(stderr, " -- Error %d", ioerr);
	fprintf(stderr, ".\n");
}

OutOfMemory(file)
char *file;
{
	TellUser("Out of Memory", file, 0);
}
-- 
		    Peter da Silva  `-_-'  peter@sugar.uu.net
		     Have you hugged  U  your wolf today?

	          Disclaimer: My typos are my own damn busines#!rne