[FIX][VM] InterpreterSupportCode squeakFilePrimsFile patch

David T. Lewis lewis at mail.msen.com
Tue Aug 8 03:58:02 UTC 2000


On Mon, Aug 07, 2000 at 05:29:22PM -0700, Tim Rowledge wrote:
> In message <20000805090235.A23671 at conch.msen.com> you wrote:
> 
> > This change declares thisSession as an external, allowing the intended
> > global access when the VM is built in pluginized form. The change
> > requires that thisSession be declared elsewhere in the interpreter
> > support code.
> David, should your file really have come through looking like:-
> 

  <munged up file snipped>

> ????

No.

Sorry, I must have messed up the <cr><lf>'s somewhere. I've attached
a fresh copy, hopefully OK this time.

> 
> Also, I think I have to disapprove of trying to use thisSession as a
> global in the context of external plugins. I suspect it is a dangerous
> assumption that all plugin-mechanisms can access global variables like
> that.
> Safer would be an accessor function like those used for nil (nilObject()
> ) and false (falseObj() ) etc.
> 

I agree. But this just seemed to be the lowest impact way to get it done.

I think that doing it "right" means adding the accessor to Interpreter.
But you would not want to have a call to time() in Interpreter, which
means there should probably be something like a getThisSession() function
elsewhere in the support code. Having gotten that far, I decided that
the real "right" thing to do would be put thisSession identification
into the image such that it would be reset on startup, but that would
mean ... well, you get the idea. At that point I said the heck with it,
just leave it as a global.

Should I try harder, or is the New Jersey approach good enough?

Dave

-------------- next part --------------
'From Squeak2.9alpha of 13 June 2000 [latest update: #2447] on 29 July 2000 at 12:02:21 pm'!
"Change Set:		thisSession-patch
Date:			29 July 2000
Author:			David T. Lewis

Declare thisSession as an external int. The variable must be declared
elsewhere in the VM support code. This permits the file primitives to
be in a loadable module, while retaining global access to thisSession
for other pluggable modules.

A better, but more complicated, solution might be to put thisSession into
the VM, and to provide an accessor method. For now, I don't want to
make that many changes just to fix the declarations."!


!InterpreterSupportCode class methodsFor: 'source files' stamp: 'dtl 7/29/2000 11:52'!
squeakFilePrimsFile

	^ '#include "sq.h"
#ifndef NO_STD_FILE_SUPPORT
#include "FilePlugin.h"

/***
	The state of a file is kept in the following structure,
	which is stored directly in a Squeak bytes object.
	NOTE: The Squeak side is responsible for creating an
	object with enough room to sto!
!
re sizeof(SQFile) bytes.

	The session ID is used to detect stale file objects--
	files that were still open when an image was written.
	The file pointer of such files is meaningless.

	Files are always opened in binary mode; Smalltalk code
	does (or someday will do) line-end conversion if needed.

	Writeable files are opened read/write. The stdio spec
	requires that a positioning operation be done when
	switching between reading and writing of a read/write
	filestream. The lastOp field records whether the last
	operation was a read or write operation, allowing this
	positioning operation to be done automatically if needed.

	typedef struct {
		File	*file;
		int		sessionID;
		int		writable;
		int		fileSize;
		int		lastOp;  // 0 = uncommitted, 1 = read, 2 = write //
	} SQFile;

***/

/*** Constants ***/
#define UNCOMMITTED	0
#define READ_OP		1
#define WRITE_OP	2

#ifndef SEEK_SET
#define SEEK_SET	0
#define SEEK_CUR	1
#define SEEK_END	2
#endif

/*** Variables ***/
extern int thi!
!
sSession;
extern struct VirtualMachine * interpreterProxy;


int sqFileAtEnd(SQFile *f) {
	/* Return true if the file''s read/write head is at the end of the file. */

	if (!!sqFileValid(f)) return interpreterProxy->success(false);
	return ftell(f->file) == f->fileSize;
}

int sqFileClose(SQFile *f) {
	/* Close the given file. */

	if (!!sqFileValid(f)) return interpreterProxy->success(false);
	fclose(f->file);
	f->file = NULL;
	f->sessionID = 0;
	f->writable = false;
	f->fileSize = 0;
	f->lastOp = UNCOMMITTED;
}

int sqFileDeleteNameSize(int sqFileNameIndex, int sqFileNameSize) {
	char cFileName[1000];
	int i, err;

	if (sqFileNameSize >= 1000) {
		return interpreterProxy->success(false);
	}

	/* copy the file name into a null-terminated C string */
	sqFilenameFromString(cFileName, sqFileNameIndex, sqFileNameSize);

	if (!!plugInAllowAccessToFilePath(cFileName, sqFileNameSize)) {
		return interpreterProxy->success(false);
	}


	err = remove(cFileName);
	if (err) {
		return in!
!
terpreterProxy->success(false);
	}
}

int sqFileGetPosition(SQFile *f) {
	/* Return the current position of the file''s read/write head. */

	int position;

	if (!!sqFileValid(f)) return interpreterProxy->success(false);
	position = ftell(f->file);
	if (position < 0) return interpreterProxy->success(false);
	return position;
}

int sqFileInit(void) {
	/* Create a session ID that is unlikely to be repeated.
	   Zero is never used for a valid session number.
	   Should be called once at startup time.
	*/

	thisSession = clock() + time(NULL);
	if (thisSession == 0) thisSession = 1;	/* don''t use 0 */
	return 1;
}

int sqFileShutdown(void) {
	return 1;
}

int sqFileOpen(SQFile *f, int sqFileNameIndex, int sqFileNameSize, int writeFlag) {
	/* Opens the given file using the supplied sqFile structure
	   to record its state. Fails with no side effects if f is
	   already open. Files are always opened in binary mode;
	   Squeak must take care of any line-end character mapping.
	*/

	c!
!
har cFileName[1001];
	int i;

	/* don''t open an already open file */
	if (sqFileValid(f)) return interpreterProxy->success(false);

	/* copy the file name into a null-terminated C string */
	if (sqFileNameSize > 1000) {
		return interpreterProxy->success(false);
	}
	sqFilenameFromString(cFileName, sqFileNameIndex, sqFileNameSize);

	if (!!plugInAllowAccessToFilePath(cFileName, sqFileNameSize)) {
		return interpreterProxy->success(false);
	}

	if (writeFlag) {
		/* First try to open an existing file read/write: */
		f->file = fopen(cFileName, "r+b");
		if (f->file == NULL) {
			/* Previous call fails if file does not exist. In that case,
			   try opening it in write mode to create a new, empty file.
			*/
			f->file = fopen(cFileName, "w+b");
			if (f->file !!= NULL) {
				/* set the type and creator of newly created Mac files */
				dir_SetMacFileTypeAndCreator((char *)sqFileNameIndex, sqFileNameSize, "TEXT", "R*ch");	
			}
		}
		f->writable = true;
	} else {
		f->file = fop!
!
en(cFileName, "rb");
		f->writable = false;
	}

	if (f->file == NULL) {
		f->sessionID = 0;
		f->fileSize = 0;
		return interpreterProxy->success(false);
	} else {
		f->sessionID = thisSession;
		/* compute and cache file size */
		fseek(f->file, 0, SEEK_END);
		f->fileSize = ftell(f->file);
		fseek(f->file, 0, SEEK_SET);
	}
	f->lastOp = UNCOMMITTED;
}

int sqFileReadIntoAt(SQFile *f, int count, int byteArrayIndex, int startIndex) {
	/* Read count bytes from the given file into byteArray starting at
	   startIndex. byteArray is the address of the first byte of a
	   Squeak bytes object (e.g. String or ByteArray). startIndex
	   is a zero-based index; that is a startIndex of 0 starts writing
	   at the first byte of byteArray.
	*/

	char *dst;
	int bytesRead;

	if (!!sqFileValid(f)) return interpreterProxy->success(false);
	if (f->writable && (f->lastOp == WRITE_OP)) fseek(f->file, 0, SEEK_CUR);  /* seek between writing and reading */
	dst = (char *) (byteArrayIndex + startInde!
!
x);
	bytesRead = fread(dst, 1, count, f->file);
	f->lastOp = READ_OP;
	return bytesRead;
}

int sqFileRenameOldSizeNewSize(int oldNameIndex, int oldNameSize, int newNameIndex, int newNameSize) {
	char cOldName[1000], cNewName[1000];
	int i, err;

	if ((oldNameSize >= 1000) || (newNameSize >= 1000)) {
		return interpreterProxy->success(false);
	}

	/* copy the file names into null-terminated C strings */
	sqFilenameFromString(cOldName, oldNameIndex, oldNameSize);

	sqFilenameFromString(cNewName, newNameIndex, newNameSize);

	if (!!plugInAllowAccessToFilePath(cOldName, oldNameSize) ||
		!!plugInAllowAccessToFilePath(cNewName, newNameSize)) {
		return interpreterProxy->success(false);
	}

	err = rename(cOldName, cNewName);
	if (err) {
		return interpreterProxy->success(false);
	}
}

int sqFileSetPosition(SQFile *f, int position) {
	/* Set the file''s read/write head to the given position. */

	if (!!sqFileValid(f)) return interpreterProxy->success(false);
	fseek(f->file, position!
!
, SEEK_SET);
	f->lastOp = UNCOMMITTED;
}

int sqFileSize(SQFile *f) {
	/* Return the length of the given file. */

	if (!!sqFileValid(f)) return interpreterProxy->success(false);
	return f->fileSize;
}

int sqFileValid(SQFile *f) {
	return (
		(f !!= NULL) &&
		(f->file !!= NULL) &&
		(f->sessionID == thisSession));
}

int sqFileWriteFromAt(SQFile *f, int count, int byteArrayIndex, int startIndex) {
	/* Write count bytes to the given writable file starting at startIndex
	   in the given byteArray. (See comment in sqFileReadIntoAt for interpretation
	   of byteArray and startIndex).
	*/

	char *src;
	int bytesWritten, position;

	if (!!(sqFileValid(f) && f->writable)) return interpreterProxy->success(false);
	if (f->lastOp == READ_OP) fseek(f->file, 0, SEEK_CUR);  /* seek between reading and writing */
	src = (char *) (byteArrayIndex + startIndex);
	bytesWritten = fwrite(src, 1, count, f->file);

	position = ftell(f->file);
	if (position > f->fileSize) {
		f->fileSize = positio!
!
n;  /* update file size */
	}

	if (bytesWritten !!= count) {
		interpreterProxy->success(false);
	}
	f->lastOp = WRITE_OP;
	return bytesWritten;
}
#endif /* NO_STD_FILE_SUPPORT */

'
! !


More information about the Squeak-dev mailing list