/* Automatically generated by
	VMPluginCodeGenerator VMMaker.oscog-eem.2498 uuid: f4233232-2c6b-452e-bdab-b814d48cc4a8
   from
	FilePlugin VMMaker.oscog-eem.2498 uuid: f4233232-2c6b-452e-bdab-b814d48cc4a8
 */
static char __buildInfo[] = "FilePlugin VMMaker.oscog-eem.2498 uuid: f4233232-2c6b-452e-bdab-b814d48cc4a8 " __DATE__ ;



#include "config.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
#include "sqConfig.h"			/* Configuration options */
#include "sqVirtualMachine.h"	/*  The virtual machine proxy definition */
#include "sqPlatformSpecific.h"	/* Platform specific definitions */

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#ifdef SQUEAK_BUILTIN_PLUGIN
# undef EXPORT
# define EXPORT(returnType) static returnType
#endif

#include "FilePlugin.h"
#include "sqMemoryAccess.h"


/*** Constants ***/
#if !defined(COGMTVM) /* Allow this to be overridden on the compiler command line */
# define COGMTVM 0
#endif
#define DirBadPath 2
#define DirNoMoreEntries 1
#if !defined(PharoVM) /* Allow this to be overridden on the compiler command line */
# define PharoVM 0
#endif
#define PrimErrBadArgument 3
#define PrimErrBadIndex 4
#define PrimErrInappropriate 6
#define PrimErrNoMemory 9
#define PrimErrObjectMayMove 14
#define PrimErrUnsupported 7
#define PrimNoErr 0
#if !defined(SPURVM) /* Allow this to be overridden on the compiler command line */
# define SPURVM 1
#endif


/*** Function Prototypes ***/
static sqInt connectToFdwrite(int fd, sqInt writeFlag);
static sqInt connectToFilewrite(void *cfile, sqInt writeFlag);
EXPORT(sqInt) fileOpenNamesizewritesecure(char *nameIndex, sqInt nameSize, sqInt writeFlag, sqInt secureFlag);
EXPORT(sqInt) fileOpenNewNamesizesecure(char *nameIndex, sqInt nameSize, sqInt secureFlag);
extern usqIntptr_t fileRecordSize(void);
extern SQFile * fileValueOf(sqInt objectPointer);
EXPORT(const char*) getModuleName(void);
EXPORT(sqInt) initialiseModule(void);
static sqInt makeDirEntryNamesizecreateDatemodDateisDirfileSize(char *entryName, sqInt entryNameSize, sqInt createDate, sqInt modifiedDate, sqInt dirFlag, squeakFileOffsetType fileSize);
#if PharoVM
static sqInt makeDirEntryNamesizecreateDatemodDateisDirfileSizeposixPermissionsisSymlink(char *entryName, sqInt entryNameSize, sqInt createDate, sqInt modifiedDate, sqInt dirFlag, squeakFileOffsetType fileSize, sqInt posixPermissions, sqInt symlinkFlag);
#endif /* PharoVM */
EXPORT(sqInt) moduleUnloaded(char *aModuleName);
static void * pointerFrom(sqInt pointerByteArray);
EXPORT(sqInt) primitiveConnectToFile(void);
EXPORT(sqInt) primitiveConnectToFileDescriptor(void);
EXPORT(sqInt) primitiveDirectoryCreate(void);
EXPORT(sqInt) primitiveDirectoryDelete(void);
EXPORT(sqInt) primitiveDirectoryDelimitor(void);
EXPORT(sqInt) primitiveDirectoryEntry(void);
EXPORT(sqInt) primitiveDirectoryGetMacTypeAndCreator(void);
EXPORT(sqInt) primitiveDirectoryLookup(void);
EXPORT(sqInt) primitiveDirectorySetMacTypeAndCreator(void);
EXPORT(sqInt) primitiveDisableFileAccess(void);
EXPORT(sqInt) primitiveFileAtEnd(void);
EXPORT(sqInt) primitiveFileClose(void);
EXPORT(sqInt) primitiveFileDelete(void);
EXPORT(sqInt) primitiveFileDescriptorType(void);
EXPORT(sqInt) primitiveFileFlush(void);
EXPORT(sqInt) primitiveFileGetPosition(void);
EXPORT(sqInt) primitiveFileOpen(void);
EXPORT(sqInt) primitiveFileOpenNew(void);
EXPORT(sqInt) primitiveFileRead(void);
static sqInt primitiveFileReadWithoutPinning(void);
static sqInt primitiveFileReadWithPinning(void);
EXPORT(sqInt) primitiveFileRename(void);
EXPORT(sqInt) primitiveFileSetPosition(void);
EXPORT(sqInt) primitiveFileSize(void);
EXPORT(sqInt) primitiveFileStdioHandles(void);
EXPORT(sqInt) primitiveFileSync(void);
EXPORT(sqInt) primitiveFileTruncate(void);
EXPORT(sqInt) primitiveFileWrite(void);
EXPORT(sqInt) primitiveHasFileAccess(void);
EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);
EXPORT(sqInt) setMacFileTypeAndCreator(char *fileName, char *typeString, char *creatorString);
EXPORT(sqInt) shutdownModule(void);


/*** Variables ***/

#if !defined(SQUEAK_BUILTIN_PLUGIN)
static void * (*arrayValueOf)(sqInt oop);
static sqInt (*booleanValueOf)(sqInt obj);
static sqInt (*byteSizeOf)(sqInt oop);
static sqInt (*characterObjectOf)(sqInt characterCode);
static sqInt (*characterTable)(void);
static sqInt (*classArray)(void);
static sqInt (*classByteArray)(void);
static sqInt (*classString)(void);
static sqInt (*failed)(void);
static sqInt (*falseObject)(void);
static sqInt (*fetchPointerofObject)(sqInt index, sqInt oop);
static void * (*firstIndexableField)(sqInt oop);
static sqInt (*fullGC)(void);
static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size);
static sqInt (*integerObjectOf)(sqInt value);
static sqInt (*integerValueOf)(sqInt oop);
static void * (*ioLoadFunctionFrom)(char *functionName, char *moduleName);
static sqInt (*isKindOf)(sqInt oop, char *aString);
static sqInt (*isBytes)(sqInt oop);
static sqInt (*isIntegerObject)(sqInt objectPointer);
static sqInt (*isWords)(sqInt oop);
static sqInt (*isWordsOrBytes)(sqInt oop);
static sqInt (*methodReturnBool)(sqInt boolean);
static sqInt (*methodReturnInteger)(sqInt integer);
static sqInt (*methodReturnValue)(sqInt oop);
static sqInt (*nilObject)(void);
static sqInt (*pop)(sqInt nItems);
static sqInt (*popthenPush)(sqInt nItems, sqInt oop);
static sqInt (*popRemappableOop)(void);
static sqInt (*positive32BitIntegerFor)(unsigned int integerValue);
static usqInt (*positive32BitValueOf)(sqInt oop);
static sqInt (*positive64BitIntegerFor)(usqLong integerValue);
static usqLong (*positive64BitValueOf)(sqInt oop);
static usqIntptr_t (*positiveMachineIntegerValueOf)(sqInt oop);
static sqInt (*primitiveFail)(void);
static sqInt (*primitiveFailFor)(sqInt reasonCode);
static sqInt (*primitiveFailForOSError)(sqLong osError);
static sqInt (*primitiveFailureCode)(void);
static sqInt (*pushRemappableOop)(sqInt oop);
static sqInt (*slotSizeOf)(sqInt oop);
static sqInt (*stSizeOf)(sqInt oop);
static sqInt (*stackIntegerValue)(sqInt offset);
static sqInt (*stackValue)(sqInt offset);
static sqInt (*storePointerofObjectwithValue)(sqInt index, sqInt oop, sqInt valuePointer);
static void (*tenuringIncrementalGC)(void);
static sqInt (*topRemappableOop)(void);
static sqInt (*trueObject)(void);
#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
extern void * arrayValueOf(sqInt oop);
extern sqInt booleanValueOf(sqInt obj);
extern sqInt byteSizeOf(sqInt oop);
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
extern sqInt characterObjectOf(sqInt characterCode);
#else
# define characterObjectOf(characterCode) 0
#endif
extern sqInt characterTable(void);
extern sqInt classArray(void);
extern sqInt classByteArray(void);
extern sqInt classString(void);
extern sqInt failed(void);
extern sqInt falseObject(void);
extern sqInt fetchPointerofObject(sqInt index, sqInt oop);
extern void * firstIndexableField(sqInt oop);
extern sqInt fullGC(void);
extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size);
extern sqInt integerObjectOf(sqInt value);
extern sqInt integerValueOf(sqInt oop);
extern void * ioLoadFunctionFrom(char *functionName, char *moduleName);
extern sqInt isKindOf(sqInt oop, char *aString);
extern sqInt isBytes(sqInt oop);
#if !defined(isIntegerObject)
extern sqInt isIntegerObject(sqInt objectPointer);
#endif
extern sqInt isWords(sqInt oop);
extern sqInt isWordsOrBytes(sqInt oop);
extern sqInt methodReturnBool(sqInt boolean);
extern sqInt methodReturnInteger(sqInt integer);
extern sqInt methodReturnValue(sqInt oop);
extern sqInt nilObject(void);
extern sqInt pop(sqInt nItems);
extern sqInt popthenPush(sqInt nItems, sqInt oop);
extern sqInt popRemappableOop(void);
extern sqInt positive32BitIntegerFor(unsigned int integerValue);
extern usqInt positive32BitValueOf(sqInt oop);
extern sqInt positive64BitIntegerFor(usqLong integerValue);
extern usqLong positive64BitValueOf(sqInt oop);
extern usqIntptr_t positiveMachineIntegerValueOf(sqInt oop);
extern sqInt primitiveFail(void);
extern sqInt primitiveFailFor(sqInt reasonCode);
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 14)
extern sqInt primitiveFailForOSError(sqLong osError);
#else
# define primitiveFailForOSError(osError) 0
#endif
extern sqInt primitiveFailureCode(void);
extern sqInt pushRemappableOop(sqInt oop);
extern sqInt slotSizeOf(sqInt oop);
extern sqInt stSizeOf(sqInt oop);
extern sqInt stackIntegerValue(sqInt offset);
extern sqInt stackValue(sqInt offset);
extern sqInt storePointerofObjectwithValue(sqInt index, sqInt oop, sqInt valuePointer);
extern void tenuringIncrementalGC(void);
extern sqInt topRemappableOop(void);
extern sqInt trueObject(void);
extern
#endif
struct VirtualMachine* interpreterProxy;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"FilePlugin VMMaker.oscog-eem.2498 (i)"
#else
	"FilePlugin VMMaker.oscog-eem.2498 (e)"
#endif
;
static void * sCCPfn;
static void * sCDFfn;
static void * sCDPfn;
static void * sCGFTfn;
static void * sCLPfn;
static void * sCOFfn;
static void * sCRFfn;
static void * sCSFTfn;
static void * sDFAfn;
static void * sHFAfn;



/*	Connect to the supplied file descriptor. Answer the file oop.
	On POSIX platforms this translates to fdopen().
	writeFlag must be compatible with the existing file access. */

	/* FilePlugin>>#connectToFd:write: */
static sqInt
connectToFdwrite(int fd, sqInt writeFlag)
{
    SQFile *file;
    sqInt fileOop;

	fileOop = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
	/* begin fileValueOf: */
	if (!((isBytes(fileOop))
		 && ((byteSizeOf(fileOop)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(fileOop);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqConnectToFileDescriptor(file, fd, writeFlag);
	}
	return fileOop;
}


/*	Open the FILE* as file. Answer the file oop.
	writeFlag must be compatible with the existing file access. */

	/* FilePlugin>>#connectToFile:write: */
static sqInt
connectToFilewrite(void *cfile, sqInt writeFlag)
{
    SQFile *file;
    sqInt fileOop;

	fileOop = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
	/* begin fileValueOf: */
	if (!((isBytes(fileOop))
		 && ((byteSizeOf(fileOop)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(fileOop);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqConnectToFile(file, cfile, writeFlag);
	}
	return fileOop;
}


/*	Open the named file, possibly checking security. Answer the file oop. */

	/* FilePlugin>>#fileOpenName:size:write:secure: */
EXPORT(sqInt)
fileOpenNamesizewritesecure(char *nameIndex, sqInt nameSize, sqInt writeFlag, sqInt secureFlag)
{
    SQFile *file;
    sqInt fileOop;
    sqInt okToOpen;

	fileOop = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
	/* begin fileValueOf: */
	if (!((isBytes(fileOop))
		 && ((byteSizeOf(fileOop)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(fileOop);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		if (secureFlag) {

			/* If the security plugin can be loaded, use it to check for permission.
			   If not, assume it's ok */
			if (sCOFfn != 0) {
				okToOpen = ((sqInt (*) (char *, sqInt, sqInt)) sCOFfn)(nameIndex, nameSize, writeFlag);
				if (!okToOpen) {
					primitiveFail();
				}
			}
		}
	}
	if (!(failed())) {
		sqFileOpen(file, nameIndex, nameSize, writeFlag);
	}
	return fileOop;
}


/*	Open the new named file, possibly checking security. Answer the file oop. */

	/* FilePlugin>>#fileOpenNewName:size:secure: */
EXPORT(sqInt)
fileOpenNewNamesizesecure(char *nameIndex, sqInt nameSize, sqInt secureFlag)
{
    sqInt exists;
    SQFile *file;
    sqInt fileOop;
    sqInt okToOpen;

	fileOop = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
	/* begin fileValueOf: */
	if (!((isBytes(fileOop))
		 && ((byteSizeOf(fileOop)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(fileOop);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		if (secureFlag) {

			/* If the security plugin can be loaded, use it to check for permission.
			   If not, assume it's ok */
			if (sCOFfn != 0) {
				okToOpen = ((sqInt (*) (char *, sqInt, sqInt)) sCOFfn)(nameIndex, nameSize, true);
				if (!okToOpen) {
					primitiveFail();
				}
			}
		}
	}
	if (!(failed())) {
		exists = 0;
		sqFileOpenNew(file, nameIndex, nameSize, &exists);
		if ((failed())
		 && (exists)) {
			primitiveFailFor(PrimErrInappropriate);
		}
	}
	return fileOop;
}


/*	Return the size of a Smalltalk file record in bytes. */

	/* FilePlugin>>#fileRecordSize */
usqIntptr_t
fileRecordSize(void)
{
	return sizeof(SQFile);
}


/*	Return a pointer to the first byte of of the file record within the given
	Smalltalk object, or nil if objectPointer is not a file record.
 */

	/* FilePlugin>>#fileValueOf: */
SQFile *
fileValueOf(sqInt objectPointer)
{
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		return null;
	}
	return firstIndexableField(objectPointer);
}


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

	/* InterpreterPlugin>>#getModuleName */
EXPORT(const char*)
getModuleName(void)
{
	return moduleName;
}

	/* FilePlugin>>#initialiseModule */
EXPORT(sqInt)
initialiseModule(void)
{
	sCCPfn = ioLoadFunctionFrom("secCanCreatePathOfSize", "SecurityPlugin");
	sCDPfn = ioLoadFunctionFrom("secCanDeletePathOfSize", "SecurityPlugin");
	sCGFTfn = ioLoadFunctionFrom("secCanGetFileTypeOfSize", "SecurityPlugin");
	sCLPfn = ioLoadFunctionFrom("secCanListPathOfSize", "SecurityPlugin");
	sCSFTfn = ioLoadFunctionFrom("secCanSetFileTypeOfSize", "SecurityPlugin");
	sDFAfn = ioLoadFunctionFrom("secDisableFileAccess", "SecurityPlugin");
	sCDFfn = ioLoadFunctionFrom("secCanDeleteFileOfSize", "SecurityPlugin");
	sCOFfn = ioLoadFunctionFrom("secCanOpenFileOfSizeWritable", "SecurityPlugin");
	sCRFfn = ioLoadFunctionFrom("secCanRenameFileOfSize", "SecurityPlugin");
	sHFAfn = ioLoadFunctionFrom("secHasFileAccess", "SecurityPlugin");
	return sqFileInit();
}

	/* FilePlugin>>#makeDirEntryName:size:createDate:modDate:isDir:fileSize: */
static sqInt
makeDirEntryNamesizecreateDatemodDateisDirfileSize(char *entryName, sqInt entryNameSize, sqInt createDate, sqInt modifiedDate, sqInt dirFlag, squeakFileOffsetType fileSize)
{
    sqInt createDateOop;
    sqInt fileSizeOop;
    sqInt i;
    sqInt modDateOop;
    sqInt nameString;
    sqInt results;
    char *stringPtr;


	/* allocate storage for results, remapping newly allocated
	   oops if required in case GC happens during allocation */
	results = instantiateClassindexableSize(classArray(), 5);
	
#if SPURVM
	nameString = instantiateClassindexableSize(classString(), entryNameSize);
	createDateOop = positive32BitIntegerFor(createDate);
	modDateOop = positive32BitIntegerFor(modifiedDate);
	fileSizeOop = positive64BitIntegerFor(fileSize);

#else /* SPURVM */
	pushRemappableOop(results);
	nameString = instantiateClassindexableSize(classString(), entryNameSize);
		pushRemappableOop(nameString);
	createDateOop = positive32BitIntegerFor(createDate);
		pushRemappableOop(createDateOop);
	modDateOop = positive32BitIntegerFor(modifiedDate);
		pushRemappableOop(modDateOop);
	fileSizeOop = positive64BitIntegerFor(fileSize);
	modDateOop = popRemappableOop();
	createDateOop = popRemappableOop();
	nameString = popRemappableOop();
	results = popRemappableOop()
#endif /* SPURVM */
;
	stringPtr = firstIndexableField(nameString);
	for (i = 0; i < entryNameSize; i += 1) {
		stringPtr[i] = (entryName[i]);
	}
	storePointerofObjectwithValue(0, results, nameString);
	storePointerofObjectwithValue(1, results, createDateOop);
	storePointerofObjectwithValue(2, results, modDateOop);
	storePointerofObjectwithValue(3, results, (dirFlag
		? trueObject()
		: falseObject()));
	storePointerofObjectwithValue(4, results, fileSizeOop);
	return results;
}

	/* FilePlugin>>#makeDirEntryName:size:createDate:modDate:isDir:fileSize:posixPermissions:isSymlink: */
#if PharoVM
static sqInt
makeDirEntryNamesizecreateDatemodDateisDirfileSizeposixPermissionsisSymlink(char *entryName, sqInt entryNameSize, sqInt createDate, sqInt modifiedDate, sqInt dirFlag, squeakFileOffsetType fileSize, sqInt posixPermissions, sqInt symlinkFlag)
{
    sqInt createDateOop;
    sqInt fileSizeOop;
    sqInt i;
    sqInt modDateOop;
    sqInt nameString;
    sqInt posixPermissionsOop;
    sqInt results;
    char *stringPtr;


	/* allocate storage for results, remapping newly allocated
	   oops if required in case GC happens during allocation */
	results = instantiateClassindexableSize(classArray(), 7);
	
#if SPURVM
	nameString = instantiateClassindexableSize(classString(), entryNameSize);
	createDateOop = positive32BitIntegerFor(createDate);
	modDateOop = positive32BitIntegerFor(modifiedDate);
	fileSizeOop = positive64BitIntegerFor(fileSize);
	posixPermissionsOop = positive32BitIntegerFor(posixPermissions);

#else /* SPURVM */
	pushRemappableOop(results);
	nameString = instantiateClassindexableSize(classString(), entryNameSize);
		pushRemappableOop(nameString);
	createDateOop = positive32BitIntegerFor(createDate);
		pushRemappableOop(createDateOop);
	modDateOop = positive32BitIntegerFor(modifiedDate);
		pushRemappableOop(modDateOop);
	fileSizeOop = positive64BitIntegerFor(fileSize);
		pushRemappableOop(fileSizeOop);
	posixPermissionsOop = positive32BitIntegerFor(posixPermissions);
	fileSizeOop = popRemappableOop();
	modDateOop = popRemappableOop();
	createDateOop = popRemappableOop();
	nameString = popRemappableOop();
	results = popRemappableOop()
#endif /* SPURVM */
;
	stringPtr = firstIndexableField(nameString);
	for (i = 0; i < entryNameSize; i += 1) {
		stringPtr[i] = (entryName[i]);
	}
	storePointerofObjectwithValue(0, results, nameString);
	storePointerofObjectwithValue(1, results, createDateOop);
	storePointerofObjectwithValue(2, results, modDateOop);
	storePointerofObjectwithValue(3, results, (dirFlag
		? trueObject()
		: falseObject()));
	storePointerofObjectwithValue(4, results, fileSizeOop);
	storePointerofObjectwithValue(5, results, posixPermissionsOop);
	storePointerofObjectwithValue(6, results, (symlinkFlag
		? trueObject()
		: falseObject()));
	return results;
}
#endif /* PharoVM */


/*	The module with the given name was just unloaded.
	Make sure we have no dangling references. */

	/* FilePlugin>>#moduleUnloaded: */
EXPORT(sqInt)
moduleUnloaded(char *aModuleName)
{
	if ((strcmp(aModuleName, "SecurityPlugin")) == 0) {

		/* The security plugin just shut down. How odd. */
		sCCPfn = (sCDPfn = (sCGFTfn = (sCLPfn = (sCSFTfn = (sDFAfn = (sCDFfn = (sCOFfn = (sCRFfn = (sHFAfn = 0)))))))));
	}
	return 0;
}


/*	Answer the machine address contained in anExternalAddressOop. */

	/* FilePlugin>>#pointerFrom: */
static void *
pointerFrom(sqInt pointerByteArray)
{
    union {void *address; unsigned char bytes[sizeof(void *)];} addressUnion;
    sqInt idx;
    unsigned char *ptr;

	if (!((isKindOf(pointerByteArray, "ByteArray"))
		 && ((stSizeOf(pointerByteArray)) == (sizeof(void *))))) {
		return primitiveFailFor(PrimErrBadArgument);
	}
	ptr = arrayValueOf(pointerByteArray);
	if (failed()) {
		return null;
	}
	idx = 0;
	while (idx < (sizeof(void *))) {
		addressUnion.bytes[idx] = ptr[idx];
		idx += 1;
	}
	return addressUnion.address;
}


/*	Connect to the file with the supplied FILE* and writeFlag.
	FILE* must be supplied in a byte object (ByteArray) with the platform
	address size.
	writeFlag must be a boolean and compatible with the existing file access.
 */

	/* FilePlugin>>#primitiveConnectToFile */
EXPORT(sqInt)
primitiveConnectToFile(void)
{
    void *cfile;
    sqInt cfileOop;
    SQFile *file;
    sqInt fileOop;
    sqInt filePointer;
    sqInt writeFlag;

	writeFlag = booleanValueOf(stackValue(0));
	cfileOop = stackValue(1);
	cfile = pointerFrom(cfileOop);
	if (failed()) {

		/* Ensure that the appropriate failure code has been set */
		return primitiveFailFor(PrimErrBadArgument);
	}
	/* begin connectToFile:write: */
	fileOop = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
	/* begin fileValueOf: */
	if (!((isBytes(fileOop))
		 && ((byteSizeOf(fileOop)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(fileOop);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqConnectToFile(file, cfile, writeFlag);
	}
	filePointer = fileOop;
	if (!(failed())) {
		methodReturnValue(filePointer);
	}
	return 0;
}


/*	Connect to the existing file identified by fileDescriptor.
	fileDescriptor must be an integer.
	writeFlag is aboolean indicating whether to open in read or write mode and
	must be compatible with the existing file access.
 */

	/* FilePlugin>>#primitiveConnectToFileDescriptor */
EXPORT(sqInt)
primitiveConnectToFileDescriptor(void)
{
    int fd;
    sqInt fdPointer;
    SQFile *file;
    sqInt fileOop;
    sqInt filePointer;
    sqInt writeFlag;

	writeFlag = booleanValueOf(stackValue(0));
	fdPointer = stackValue(1);
	if (!(isIntegerObject(fdPointer))) {
		return primitiveFailFor(PrimErrBadArgument);
	}
	fd = integerValueOf(fdPointer);
	if (failed()) {

		/* Ensure that the appropriate failure code has been set */
		return primitiveFailFor(PrimErrBadArgument);
	}
	/* begin connectToFd:write: */
	fileOop = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
	/* begin fileValueOf: */
	if (!((isBytes(fileOop))
		 && ((byteSizeOf(fileOop)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(fileOop);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqConnectToFileDescriptor(file, fd, writeFlag);
	}
	filePointer = fileOop;
	if (!(failed())) {
		methodReturnValue(filePointer);
	}
	return 0;
}

	/* FilePlugin>>#primitiveDirectoryCreate */
EXPORT(sqInt)
primitiveDirectoryCreate(void)
{
    sqInt dirName;
    char *dirNameIndex;
    sqInt dirNameSize;
    sqInt okToCreate;

	dirName = stackValue(0);
	if (!(isBytes(dirName))) {
		return primitiveFail();
	}
	dirNameIndex = firstIndexableField(dirName);

	/* If the security plugin can be loaded, use it to check for permission.
	   If not, assume it's ok */
	dirNameSize = byteSizeOf(dirName);
	if (sCCPfn != 0) {
		okToCreate =  ((sqInt (*)(char *, sqInt))sCCPfn)(dirNameIndex, dirNameSize);
		if (!okToCreate) {
			return primitiveFail();
		}
	}
	if (!(dir_Create(dirNameIndex, dirNameSize))) {
		return primitiveFail();
	}
	pop(1);
	return 0;
}

	/* FilePlugin>>#primitiveDirectoryDelete */
EXPORT(sqInt)
primitiveDirectoryDelete(void)
{
    sqInt dirName;
    char *dirNameIndex;
    sqInt dirNameSize;
    sqInt okToDelete;

	dirName = stackValue(0);
	if (!(isBytes(dirName))) {
		return primitiveFail();
	}
	dirNameIndex = firstIndexableField(dirName);

	/* If the security plugin can be loaded, use it to check for permission.
	   If not, assume it's ok */
	dirNameSize = byteSizeOf(dirName);
	if (sCDPfn != 0) {
		okToDelete =  ((sqInt (*)(char *, sqInt))sCDPfn)(dirNameIndex, dirNameSize);
		if (!okToDelete) {
			return primitiveFail();
		}
	}
	if (!(dir_Delete(dirNameIndex, dirNameSize))) {
		return primitiveFail();
	}
	pop(1);
	return 0;
}

	/* FilePlugin>>#primitiveDirectoryDelimitor */
EXPORT(sqInt)
primitiveDirectoryDelimitor(void)
{
    sqInt ascii;

	if ((interpreterProxy->minorVersion()) >= 13) {
		popthenPush(1, characterObjectOf(dir_Delimitor()));
	}
	else {
		ascii = dir_Delimitor();
		if ((ascii >= 0)
		 && (ascii <= 0xFF)) {
			popthenPush(1, fetchPointerofObject(ascii, characterTable()));
		}
		else {
			primitiveFail();
		}
	}
	return 0;
}


/*	Two arguments - directory path, and simple file name;
	returns an array (see primitiveDirectoryLookup) describing the file or
	directory, or nil if it does not exist. 
	Primitive fails if the outer path does not identify a readable directory.
	(This is a lookup-by-name variant of primitiveDirectoryLookup.) */

	/* FilePlugin>>#primitiveDirectoryEntry */
EXPORT(sqInt)
primitiveDirectoryEntry(void)
{
    sqInt createDate;
    sqInt dirFlag;
    char entryName[256];
    sqInt entryNameSize;
    squeakFileOffsetType fileSize;
    sqInt modifiedDate;
    sqInt okToList;
    sqInt pathName;
    char *pathNameIndex;
    sqInt pathNameSize;
    sqInt posixPermissions;
    char *reqNameIndex;
    sqInt reqNameSize;
    sqInt requestedName;
    sqInt status;
    sqInt symlinkFlag;
    sqInt v;

	createDate = 0;
	dirFlag = 0;
	entryNameSize = 0;
	modifiedDate = 0;
	posixPermissions = 0;
	symlinkFlag = 0;
	v = 0;
	requestedName = stackValue(0);
	pathName = stackValue(1);
	if (!(isBytes(pathName))) {
		return primitiveFail();
	}
	pathNameIndex = firstIndexableField(pathName);
	pathNameSize = byteSizeOf(pathName);
	reqNameIndex = firstIndexableField(requestedName);
	reqNameSize = byteSizeOf(requestedName);
	okToList = (sCLPfn != 0
		? ((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, pathNameSize)
		: 1);
	status = (okToList
		? dir_EntryLookup(pathNameIndex, pathNameSize, reqNameIndex, reqNameSize, entryName, (&entryNameSize), (&createDate), (&modifiedDate), (&dirFlag), (&fileSize), (&posixPermissions), (&symlinkFlag))
		: DirNoMoreEntries);
	if (failed()) {
		return null;
	}
	if (status == DirNoMoreEntries) {

		/* no entry; return nil */
		/* pop pathName, index, rcvr */
		popthenPush(3, nilObject());
		return null;
	}
	if (status == DirBadPath) {
		return primitiveFail();
	}
	popthenPush(3, 
#  if PharoVM
		makeDirEntryNamesizecreateDatemodDateisDirfileSizeposixPermissionsisSymlink(entryName, entryNameSize, createDate, modifiedDate, dirFlag, fileSize, posixPermissions, symlinkFlag)
#  else /* PharoVM */
		makeDirEntryNamesizecreateDatemodDateisDirfileSize(entryName, entryNameSize, createDate, modifiedDate, dirFlag, fileSize)
#  endif /* PharoVM */
		);
	return 0;
}

	/* FilePlugin>>#primitiveDirectoryGetMacTypeAndCreator */
EXPORT(sqInt)
primitiveDirectoryGetMacTypeAndCreator(void)
{
    sqInt creatorString;
    char *creatorStringIndex;
    sqInt fileName;
    char *fileNameIndex;
    sqInt fileNameSize;
    sqInt okToGet;
    sqInt typeString;
    char *typeStringIndex;

	creatorString = stackValue(0);
	typeString = stackValue(1);
	fileName = stackValue(2);
	if (!((isBytes(creatorString))
		 && ((byteSizeOf(creatorString)) == 4))) {
		return primitiveFail();
	}
	if (!((isBytes(typeString))
		 && ((byteSizeOf(typeString)) == 4))) {
		return primitiveFail();
	}
	if (!(isBytes(fileName))) {
		return primitiveFail();
	}
	creatorStringIndex = firstIndexableField(creatorString);
	typeStringIndex = firstIndexableField(typeString);
	fileNameIndex = firstIndexableField(fileName);

	/* If the security plugin can be loaded, use it to check for permission.
	   If not, assume it's ok */
	fileNameSize = byteSizeOf(fileName);
	if (sCGFTfn != 0) {
		okToGet =  ((sqInt (*)(char *, sqInt))sCGFTfn)(fileNameIndex, fileNameSize);
		if (!okToGet) {
			return primitiveFail();
		}
	}
	if (!(dir_GetMacFileTypeAndCreator(fileNameIndex, fileNameSize, typeStringIndex, creatorStringIndex))) {
		return primitiveFail();
	}
	pop(3);
	return 0;
}

	/* FilePlugin>>#primitiveDirectoryLookup */
EXPORT(sqInt)
primitiveDirectoryLookup(void)
{
    sqInt createDate;
    sqInt dirFlag;
    char entryName[256];
    sqInt entryNameSize;
    squeakFileOffsetType fileSize;
    sqInt index;
    sqInt modifiedDate;
    sqInt okToList;
    sqInt pathName;
    char *pathNameIndex;
    sqInt pathNameSize;
    sqInt posixPermissions;
    sqInt status;
    sqInt symlinkFlag;
    sqInt v;

	createDate = 0;
	dirFlag = 0;
	entryNameSize = 0;
	modifiedDate = 0;
	posixPermissions = 0;
	symlinkFlag = 0;
	v = 0;
	index = stackIntegerValue(0);
	pathName = stackValue(1);
	if (!(isBytes(pathName))) {
		return primitiveFail();
	}
	pathNameIndex = firstIndexableField(pathName);
	pathNameSize = byteSizeOf(pathName);
	okToList = (sCLPfn != 0
		? ((sqInt (*)(char *, sqInt))sCLPfn)(pathNameIndex, pathNameSize)
		: 1);
	status = (okToList
		? dir_Lookup(pathNameIndex, pathNameSize, index, entryName, (&entryNameSize), (&createDate), (&modifiedDate), (&dirFlag), (&fileSize), (&posixPermissions), (&symlinkFlag))
		: DirNoMoreEntries);
	if (failed()) {
		return null;
	}
	if (status == DirNoMoreEntries) {

		/* no more entries; return nil */
		/* pop pathName, index, rcvr */
		popthenPush(3, nilObject());
		return null;
	}
	if (status == DirBadPath) {
		return primitiveFail();
	}
	popthenPush(3, 
#  if PharoVM
		makeDirEntryNamesizecreateDatemodDateisDirfileSizeposixPermissionsisSymlink(entryName, entryNameSize, createDate, modifiedDate, dirFlag, fileSize, posixPermissions, symlinkFlag)
#  else /* PharoVM */
		makeDirEntryNamesizecreateDatemodDateisDirfileSize(entryName, entryNameSize, createDate, modifiedDate, dirFlag, fileSize)
#  endif /* PharoVM */
		);
	return 0;
}

	/* FilePlugin>>#primitiveDirectorySetMacTypeAndCreator */
EXPORT(sqInt)
primitiveDirectorySetMacTypeAndCreator(void)
{
    sqInt creatorString;
    char *creatorStringIndex;
    sqInt fileName;
    char *fileNameIndex;
    sqInt fileNameSize;
    sqInt okToSet;
    sqInt typeString;
    char *typeStringIndex;

	creatorString = stackValue(0);
	typeString = stackValue(1);
	fileName = stackValue(2);
	if (!((isBytes(creatorString))
		 && ((isBytes(typeString))
		 && ((isBytes(fileName))
		 && (((byteSizeOf(creatorString)) == 4)
		 && ((byteSizeOf(typeString)) == 4)))))) {
		return primitiveFail();
	}
	creatorStringIndex = firstIndexableField(creatorString);
	typeStringIndex = firstIndexableField(typeString);
	fileNameIndex = firstIndexableField(fileName);

	/* If the security plugin can be loaded, use it to check for permission.
	   If not, assume it's ok */
	fileNameSize = byteSizeOf(fileName);
	if (sCSFTfn != 0) {
		okToSet = ((sqInt (*)(char *, sqInt))sCSFTfn)(fileNameIndex, fileNameSize);
		if (!okToSet) {
			return primitiveFail();
		}
	}
	if (!(dir_SetMacFileTypeAndCreator(fileNameIndex, fileNameSize, typeStringIndex, creatorStringIndex))) {
		return primitiveFail();
	}
	pop(3);
	return 0;
}


/*	If the security plugin can be loaded, use it to turn off file access
	If not, assume it's ok */

	/* FilePlugin>>#primitiveDisableFileAccess */
EXPORT(sqInt)
primitiveDisableFileAccess(void)
{
	if (sDFAfn != 0) {
		((sqInt (*)(void))sDFAfn)();
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileAtEnd */
EXPORT(sqInt)
primitiveFileAtEnd(void)
{
    sqInt atEnd;
    SQFile *file;
    sqInt objectPointer;

	atEnd = 0;
	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		atEnd = sqFileAtEnd(file);
	}
	if (!(failed())) {
		methodReturnBool(atEnd);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileClose */
EXPORT(sqInt)
primitiveFileClose(void)
{
    SQFile *file;
    sqInt objectPointer;

	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqFileClose(file);
	}
	if (!(failed())) {
		pop(1);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileDelete */
EXPORT(sqInt)
primitiveFileDelete(void)
{
    char *nameIndex;
    sqInt namePointer;
    sqInt nameSize;
    sqInt okToDelete;

	namePointer = stackValue(0);
	if (!(isBytes(namePointer))) {
		return primitiveFail();
	}
	nameIndex = firstIndexableField(namePointer);

	/* If the security plugin can be loaded, use it to check for permission.
	   If not, assume it's ok */
	nameSize = byteSizeOf(namePointer);
	if (sCDFfn != 0) {
		okToDelete =  ((sqInt (*)(char *, sqInt))sCDFfn)(nameIndex, nameSize);
		if (!okToDelete) {
			return primitiveFail();
		}
	}
	sqFileDeleteNameSize(nameIndex, nameSize);
	if (!(failed())) {
		pop(1);
	}
	return 0;
}


/*	Allow to test if the standard input/output files are from a console or not
	Return values:
	* -1 - Error
	* 0 - no console (windows only)
	* 1 - normal terminal (unix terminal / windows console)
	* 2 - pipe
	* 3 - file
	* 4 - cygwin terminal (windows only) */

	/* FilePlugin>>#primitiveFileDescriptorType */
EXPORT(sqInt)
primitiveFileDescriptorType(void)
{
    int fd;
    sqInt fdPointer;
    sqInt fileType;

	fdPointer = stackValue(0);
	if (!(isIntegerObject(fdPointer))) {
		return primitiveFailFor(PrimErrBadArgument);
	}
	fd = integerValueOf(fdPointer);
	if (failed()) {

		/* Ensure that the appropriate failure code has been set */
		return primitiveFailFor(PrimErrBadArgument);
	}
	fileType = sqFileDescriptorType(fd);
	methodReturnInteger(fileType);
	return 0;
}

	/* FilePlugin>>#primitiveFileFlush */
EXPORT(sqInt)
primitiveFileFlush(void)
{
    SQFile *file;
    sqInt objectPointer;

	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqFileFlush(file);
	}
	if (!(failed())) {
		pop(1);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileGetPosition */
EXPORT(sqInt)
primitiveFileGetPosition(void)
{
    SQFile *file;
    sqInt objectPointer;
    squeakFileOffsetType position;

	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		position = sqFileGetPosition(file);
	}
	if (!(failed())) {
		methodReturnValue(positive64BitIntegerFor(position));
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileOpen */
EXPORT(sqInt)
primitiveFileOpen(void)
{
    sqInt filePointer;
    char *nameIndex;
    sqInt namePointer;
    sqInt nameSize;
    sqInt writeFlag;

	writeFlag = booleanValueOf(stackValue(0));
	namePointer = stackValue(1);
	if (!(isBytes(namePointer))) {
		return primitiveFail();
	}
	nameIndex = firstIndexableField(namePointer);
	nameSize = byteSizeOf(namePointer);
	filePointer = fileOpenNamesizewritesecure(nameIndex, nameSize, writeFlag, 1);
	if (!(failed())) {
		methodReturnValue(filePointer);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileOpenNew */
EXPORT(sqInt)
primitiveFileOpenNew(void)
{
    sqInt filePointer;
    char *nameIndex;
    sqInt namePointer;
    sqInt nameSize;

	namePointer = stackValue(0);
	if (!(isBytes(namePointer))) {
		return primitiveFail();
	}
	nameIndex = firstIndexableField(namePointer);
	nameSize = byteSizeOf(namePointer);
	filePointer = fileOpenNewNamesizesecure(nameIndex, nameSize, 1);
	if (!(failed())) {
		methodReturnValue(filePointer);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileRead */
EXPORT(sqInt)
primitiveFileRead(void)
{
    sqInt array;
    sqInt array1;
    sqInt bytesRead;
    sqInt bytesRead1;
    size_t count;
    size_t count1;
    size_t elementSize;
    size_t elementSize1;
    SQFile *file;
    SQFile *file1;
    sqInt objectPointer;
    sqInt objectPointer1;
    sqInt retryCount;
    size_t slotSize;
    size_t startIndex;
    size_t startIndex1;

	
#  if SPURVM
	/* begin primitiveFileReadWithPinning */
	count = positiveMachineIntegerValueOf(stackValue(0));
	startIndex = positiveMachineIntegerValueOf(stackValue(1));
	array = stackValue(2);
	/* begin fileValueOf: */
	objectPointer = stackValue(3);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if ((failed())
	 || (!(isWordsOrBytes(array)))) {
		primitiveFailFor(PrimErrBadArgument);
		goto l2;
	}
	slotSize = slotSizeOf(array);
	if (!((startIndex >= 1)
		 && (((startIndex + count) - 1) <= slotSize))) {
		primitiveFailFor(PrimErrBadIndex);
		goto l2;
	}
	elementSize = (slotSize == 0
		? 1
		: (byteSizeOf(array)) / slotSize);
	bytesRead = sqFileReadIntoAt(file, count * elementSize, ((char *) (firstIndexableField(array))), (startIndex - 1) * elementSize);
	if (!(failed())) {
		methodReturnValue(integerObjectOf(bytesRead / elementSize));
	}
	l2:	/* end primitiveFileReadWithPinning */;
#  else /* SPURVM */
	/* begin primitiveFileReadWithoutPinning */
	retryCount = 0;
	count1 = positive32BitValueOf(stackValue(0));
	startIndex1 = positive32BitValueOf(stackValue(1));
	while (1) {
		array1 = stackValue(2);
		/* begin fileValueOf: */
		objectPointer1 = stackValue(3);
		if (!((isBytes(objectPointer1))
			 && ((byteSizeOf(objectPointer1)) == (sizeof(SQFile))))) {
			primitiveFail();
			file1 = null;
			goto l3;
		}
		file1 = firstIndexableField(objectPointer1);
	l3:	/* end fileValueOf: */;
		if ((failed())
		 || (!(isWordsOrBytes(array1)))) {
			primitiveFailFor(PrimErrBadArgument);
			goto l4;
		}
		elementSize1 = (isWords(array1)
			? 4
			: 1);
		if (!((startIndex1 >= 1)
			 && (((startIndex1 + count1) - 1) <= (slotSizeOf(array1))))) {
			primitiveFailFor(PrimErrBadIndex);
			goto l4;
		}
		bytesRead1 = sqFileReadIntoAt(file1, count1 * elementSize1, ((char *) (firstIndexableField(array1))), (startIndex1 - 1) * elementSize1);
		if (!(((primitiveFailureCode()) == PrimErrObjectMayMove)
		 && (((retryCount += 1)) <= 2))) break;
		tenuringIncrementalGC();
		primitiveFailFor(PrimNoErr);
	}
	if (!(failed())) {
		methodReturnValue(integerObjectOf(bytesRead1 / elementSize1));
	}
	l4:	/* end primitiveFileReadWithoutPinning */;
#  endif /* SPURVM */
	return 0;
}


/*	This version of primitiveFileRead is for garbage collectors without
	support for pinning.
 */

	/* FilePlugin>>#primitiveFileReadWithoutPinning */
static sqInt
primitiveFileReadWithoutPinning(void)
{
    sqInt array;
    sqInt bytesRead;
    size_t count;
    size_t elementSize;
    SQFile *file;
    sqInt objectPointer;
    sqInt retryCount;
    size_t startIndex;

	retryCount = 0;
	count = positive32BitValueOf(stackValue(0));
	startIndex = positive32BitValueOf(stackValue(1));
	while (1) {
		array = stackValue(2);
		/* begin fileValueOf: */
		objectPointer = stackValue(3);
		if (!((isBytes(objectPointer))
			 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
			primitiveFail();
			file = null;
			goto l1;
		}
		file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
		if ((failed())
		 || (!(isWordsOrBytes(array)))) {
			return primitiveFailFor(PrimErrBadArgument);
		}
		elementSize = (isWords(array)
			? 4
			: 1);
		if (!((startIndex >= 1)
			 && (((startIndex + count) - 1) <= (slotSizeOf(array))))) {
			return primitiveFailFor(PrimErrBadIndex);
		}
		bytesRead = sqFileReadIntoAt(file, count * elementSize, ((char *) (firstIndexableField(array))), (startIndex - 1) * elementSize);
		if (!(((primitiveFailureCode()) == PrimErrObjectMayMove)
		 && (((retryCount += 1)) <= 2))) break;
		tenuringIncrementalGC();
		primitiveFailFor(PrimNoErr);
	}
	if (!(failed())) {
		methodReturnValue(integerObjectOf(bytesRead / elementSize));
	}
	return 0;
}


/*	This version of primitiveFileRead is for garbage collectors that support
	pinning. 
 */

	/* FilePlugin>>#primitiveFileReadWithPinning */
static sqInt
primitiveFileReadWithPinning(void)
{
    sqInt array;
    sqInt bytesRead;
    size_t count;
    size_t elementSize;
    SQFile *file;
    sqInt objectPointer;
    size_t slotSize;
    size_t startIndex;

	count = positiveMachineIntegerValueOf(stackValue(0));
	startIndex = positiveMachineIntegerValueOf(stackValue(1));
	array = stackValue(2);
	/* begin fileValueOf: */
	objectPointer = stackValue(3);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if ((failed())
	 || (!(isWordsOrBytes(array)))) {
		return primitiveFailFor(PrimErrBadArgument);
	}
	slotSize = slotSizeOf(array);
	if (!((startIndex >= 1)
		 && (((startIndex + count) - 1) <= slotSize))) {
		return primitiveFailFor(PrimErrBadIndex);
	}
	elementSize = (slotSize == 0
		? 1
		: (byteSizeOf(array)) / slotSize);
	bytesRead = sqFileReadIntoAt(file, count * elementSize, ((char *) (firstIndexableField(array))), (startIndex - 1) * elementSize);
	if (!(failed())) {
		methodReturnValue(integerObjectOf(bytesRead / elementSize));
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileRename */
EXPORT(sqInt)
primitiveFileRename(void)
{
    char *newNameIndex;
    sqInt newNamePointer;
    sqInt newNameSize;
    sqInt okToRename;
    char *oldNameIndex;
    sqInt oldNamePointer;
    sqInt oldNameSize;

	newNamePointer = stackValue(0);
	oldNamePointer = stackValue(1);
	if (!((isBytes(newNamePointer))
		 && (isBytes(oldNamePointer)))) {
		return primitiveFail();
	}
	newNameIndex = firstIndexableField(newNamePointer);
	newNameSize = byteSizeOf(newNamePointer);
	oldNameIndex = firstIndexableField(oldNamePointer);

	/* If the security plugin can be loaded, use it to check for rename permission.
	   If not, assume it's ok */
	oldNameSize = byteSizeOf(oldNamePointer);
	if (sCRFfn != 0) {
		okToRename =  ((sqInt (*)(char *, sqInt))sCRFfn)(oldNameIndex, oldNameSize);
		if (!okToRename) {
			return primitiveFail();
		}
	}
	sqFileRenameOldSizeNewSize(oldNameIndex, oldNameSize, newNameIndex, newNameSize);
	if (!(failed())) {
		pop(2);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileSetPosition */
EXPORT(sqInt)
primitiveFileSetPosition(void)
{
    SQFile *file;
    squeakFileOffsetType newPosition;
    sqInt objectPointer;

	if ((byteSizeOf(stackValue(0))) > (sizeof(squeakFileOffsetType))) {
		return primitiveFail();
	}
	newPosition = positive64BitValueOf(stackValue(0));
	/* begin fileValueOf: */
	objectPointer = stackValue(1);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqFileSetPosition(file, newPosition);
	}
	if (!(failed())) {
		pop(2);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileSize */
EXPORT(sqInt)
primitiveFileSize(void)
{
    SQFile *file;
    sqInt objectPointer;
    squeakFileOffsetType size;

	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		size = sqFileSize(file);
	}
	if (!(failed())) {
		methodReturnValue(positive64BitIntegerFor(size));
	}
	return 0;
}


/*	Answer an Array of file handles for standard in, standard out and standard
	error, with nil in entries that are unvailable, e.g. because the platform
	does not provide
	standard error, etc. Fail if an error occurs determining the stdio
	handles, if the security plugin denies access or if memory runs out. */

	/* FilePlugin>>#primitiveFileStdioHandles */
EXPORT(sqInt)
primitiveFileStdioHandles(void)
{
    SQFile fileRecords[3];
    sqInt index;
    sqInt result;
    sqInt validMask;

	if (sHFAfn != 0) {
		if (!( ((sqInt (*)(void))sHFAfn)())) {
			return primitiveFailFor(PrimErrUnsupported);
		}
	}
	validMask = sqFileStdioHandlesInto(fileRecords);
	if (validMask < 0) {
		return primitiveFailForOSError(validMask);
	}
	result = instantiateClassindexableSize(classArray(), 3);
	if (result == null) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	pushRemappableOop(result);
	for (index = 0; index <= 2; index += 1) {
		if ((validMask & (1U << index)) != 0) {
			result = instantiateClassindexableSize(classByteArray(), sizeof(SQFile));
			if (result == null) {
				popRemappableOop();
				return primitiveFailFor(PrimErrNoMemory);
			}
			storePointerofObjectwithValue(index, topRemappableOop(), result);
			memcpy(firstIndexableField(result), (&(fileRecords[index])), sizeof(SQFile));
		}
	}
	
#  if COGMTVM
	
#  if SPURVM
#  else /* SPURVM */
	fullGC();
#  endif /* SPURVM */
#  endif /* COGMTVM */
	result = popRemappableOop();
	methodReturnValue(result);
	return 0;
}

	/* FilePlugin>>#primitiveFileSync */
EXPORT(sqInt)
primitiveFileSync(void)
{
    SQFile *file;
    sqInt objectPointer;

	/* begin fileValueOf: */
	objectPointer = stackValue(0);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqFileSync(file);
	}
	if (!(failed())) {
		pop(1);
	}
	return 0;
}


/*	ftruncate is not an ansi function so we have a macro to point to a
	suitable platform implementation
 */

	/* FilePlugin>>#primitiveFileTruncate */
EXPORT(sqInt)
primitiveFileTruncate(void)
{
    SQFile *file;
    sqInt objectPointer;
    squeakFileOffsetType truncatePosition;

	if (!(isIntegerObject(stackValue(0)))) {
		if ((byteSizeOf(stackValue(0))) > (sizeof(squeakFileOffsetType))) {
			return primitiveFail();
		}
	}
	truncatePosition = positive64BitValueOf(stackValue(0));
	/* begin fileValueOf: */
	objectPointer = stackValue(1);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if (!(failed())) {
		sqFileTruncate(file, truncatePosition);
	}
	if (!(failed())) {
		pop(2);
	}
	return 0;
}

	/* FilePlugin>>#primitiveFileWrite */
EXPORT(sqInt)
primitiveFileWrite(void)
{
    sqInt array;
    sqInt bytesWritten;
    size_t count;
    size_t elementSize;
    SQFile *file;
    sqInt objectPointer;
    size_t slotSize;
    size_t startIndex;

	count = positiveMachineIntegerValueOf(stackValue(0));
	startIndex = positiveMachineIntegerValueOf(stackValue(1));
	array = stackValue(2);
	/* begin fileValueOf: */
	objectPointer = stackValue(3);
	if (!((isBytes(objectPointer))
		 && ((byteSizeOf(objectPointer)) == (sizeof(SQFile))))) {
		primitiveFail();
		file = null;
		goto l1;
	}
	file = firstIndexableField(objectPointer);
	l1:	/* end fileValueOf: */;
	if ((failed())
	 || (!(isWordsOrBytes(array)))) {
		return primitiveFailFor(PrimErrBadArgument);
	}
	slotSize = slotSizeOf(array);
	if (!((startIndex >= 1)
		 && (((startIndex + count) - 1) <= slotSize))) {
		return primitiveFailFor(PrimErrBadIndex);
	}
	elementSize = (slotSize == 0
		? 1
		: (byteSizeOf(array)) / slotSize);
	bytesWritten = sqFileWriteFromAt(file, count * elementSize, ((char *) (firstIndexableField(array))), (startIndex - 1) * elementSize);
	if (!(failed())) {
		methodReturnValue(integerObjectOf(bytesWritten / elementSize));
	}
	return 0;
}

	/* FilePlugin>>#primitiveHasFileAccess */
EXPORT(sqInt)
primitiveHasFileAccess(void)
{
    sqInt hasAccess;


	/* If the security plugin can be loaded, use it to check .
	   If not, assume it's ok */
	if (sHFAfn != 0) {
		hasAccess =  ((sqInt (*)(void))sHFAfn)();
	}
	else {
		hasAccess = 1;
	}
	methodReturnBool(hasAccess);
	return 0;
}


/*	Note: This is coded so that it can be run in Squeak. */

	/* InterpreterPlugin>>#setInterpreter: */
EXPORT(sqInt)
setInterpreter(struct VirtualMachine *anInterpreter)
{
    sqInt ok;

	interpreterProxy = anInterpreter;
	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
	if (ok) {
		
#if !defined(SQUEAK_BUILTIN_PLUGIN)
		arrayValueOf = interpreterProxy->arrayValueOf;
		booleanValueOf = interpreterProxy->booleanValueOf;
		byteSizeOf = interpreterProxy->byteSizeOf;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
		characterObjectOf = interpreterProxy->characterObjectOf;
#else
#if !defined(characterObjectOf)
		characterObjectOf = 0;
#endif
#endif
		characterTable = interpreterProxy->characterTable;
		classArray = interpreterProxy->classArray;
		classByteArray = interpreterProxy->classByteArray;
		classString = interpreterProxy->classString;
		failed = interpreterProxy->failed;
		falseObject = interpreterProxy->falseObject;
		fetchPointerofObject = interpreterProxy->fetchPointerofObject;
		firstIndexableField = interpreterProxy->firstIndexableField;
		fullGC = interpreterProxy->fullGC;
		instantiateClassindexableSize = interpreterProxy->instantiateClassindexableSize;
		integerObjectOf = interpreterProxy->integerObjectOf;
		integerValueOf = interpreterProxy->integerValueOf;
		ioLoadFunctionFrom = interpreterProxy->ioLoadFunctionFrom;
		isKindOf = interpreterProxy->isKindOf;
		isBytes = interpreterProxy->isBytes;
		isIntegerObject = interpreterProxy->isIntegerObject;
		isWords = interpreterProxy->isWords;
		isWordsOrBytes = interpreterProxy->isWordsOrBytes;
		methodReturnBool = interpreterProxy->methodReturnBool;
		methodReturnInteger = interpreterProxy->methodReturnInteger;
		methodReturnValue = interpreterProxy->methodReturnValue;
		nilObject = interpreterProxy->nilObject;
		pop = interpreterProxy->pop;
		popthenPush = interpreterProxy->popthenPush;
		popRemappableOop = interpreterProxy->popRemappableOop;
		positive32BitIntegerFor = interpreterProxy->positive32BitIntegerFor;
		positive32BitValueOf = interpreterProxy->positive32BitValueOf;
		positive64BitIntegerFor = interpreterProxy->positive64BitIntegerFor;
		positive64BitValueOf = interpreterProxy->positive64BitValueOf;
		positiveMachineIntegerValueOf = interpreterProxy->positiveMachineIntegerValueOf;
		primitiveFail = interpreterProxy->primitiveFail;
		primitiveFailFor = interpreterProxy->primitiveFailFor;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 14)
		primitiveFailForOSError = interpreterProxy->primitiveFailForOSError;
#else
#if !defined(primitiveFailForOSError)
		primitiveFailForOSError = 0;
#endif
#endif
		primitiveFailureCode = interpreterProxy->primitiveFailureCode;
		pushRemappableOop = interpreterProxy->pushRemappableOop;
		slotSizeOf = interpreterProxy->slotSizeOf;
		stSizeOf = interpreterProxy->stSizeOf;
		stackIntegerValue = interpreterProxy->stackIntegerValue;
		stackValue = interpreterProxy->stackValue;
		storePointerofObjectwithValue = interpreterProxy->storePointerofObjectwithValue;
		tenuringIncrementalGC = interpreterProxy->tenuringIncrementalGC;
		topRemappableOop = interpreterProxy->topRemappableOop;
		trueObject = interpreterProxy->trueObject;
#endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
	}
	return ok;
}


/*	Exported entry point for the VM. Needed for image saving only and no-op on
	anything but Macs.
 */

	/* FilePlugin>>#setMacFile:Type:AndCreator: */
EXPORT(sqInt)
setMacFileTypeAndCreator(char *fileName, char *typeString, char *creatorString)
{
	return dir_SetMacFileTypeAndCreator(fileName, strlen(fileName), typeString, creatorString);
}

	/* FilePlugin>>#shutdownModule */
EXPORT(sqInt)
shutdownModule(void)
{
	return sqFileShutdown();
}


#ifdef SQUEAK_BUILTIN_PLUGIN

static char _m[] = "FilePlugin";
void* FilePlugin_exports[][3] = {
	{(void*)_m, "fileOpenNamesizewritesecure", (void*)fileOpenNamesizewritesecure},
	{(void*)_m, "fileOpenNewNamesizesecure", (void*)fileOpenNewNamesizesecure},
	{(void*)_m, "getModuleName", (void*)getModuleName},
	{(void*)_m, "initialiseModule", (void*)initialiseModule},
	{(void*)_m, "moduleUnloaded", (void*)moduleUnloaded},
	{(void*)_m, "primitiveConnectToFile\000\001", (void*)primitiveConnectToFile},
	{(void*)_m, "primitiveConnectToFileDescriptor\000\000", (void*)primitiveConnectToFileDescriptor},
	{(void*)_m, "primitiveDirectoryCreate\000\001", (void*)primitiveDirectoryCreate},
	{(void*)_m, "primitiveDirectoryDelete\000\001", (void*)primitiveDirectoryDelete},
	{(void*)_m, "primitiveDirectoryDelimitor\000\377", (void*)primitiveDirectoryDelimitor},
	{(void*)_m, "primitiveDirectoryEntry\000\001", (void*)primitiveDirectoryEntry},
	{(void*)_m, "primitiveDirectoryGetMacTypeAndCreator\000\001", (void*)primitiveDirectoryGetMacTypeAndCreator},
	{(void*)_m, "primitiveDirectoryLookup\000\001", (void*)primitiveDirectoryLookup},
	{(void*)_m, "primitiveDirectorySetMacTypeAndCreator\000\001", (void*)primitiveDirectorySetMacTypeAndCreator},
	{(void*)_m, "primitiveDisableFileAccess\000\377", (void*)primitiveDisableFileAccess},
	{(void*)_m, "primitiveFileAtEnd\000\001", (void*)primitiveFileAtEnd},
	{(void*)_m, "primitiveFileClose\000\001", (void*)primitiveFileClose},
	{(void*)_m, "primitiveFileDelete\000\001", (void*)primitiveFileDelete},
	{(void*)_m, "primitiveFileDescriptorType\000\000", (void*)primitiveFileDescriptorType},
	{(void*)_m, "primitiveFileFlush\000\001", (void*)primitiveFileFlush},
	{(void*)_m, "primitiveFileGetPosition\000\001", (void*)primitiveFileGetPosition},
	{(void*)_m, "primitiveFileOpen\000\002", (void*)primitiveFileOpen},
	{(void*)_m, "primitiveFileOpenNew\000\002", (void*)primitiveFileOpenNew},
	{(void*)_m, "primitiveFileRead\000\001", (void*)primitiveFileRead},
	{(void*)_m, "primitiveFileRename\000\001", (void*)primitiveFileRename},
	{(void*)_m, "primitiveFileSetPosition\000\001", (void*)primitiveFileSetPosition},
	{(void*)_m, "primitiveFileSize\000\001", (void*)primitiveFileSize},
	{(void*)_m, "primitiveFileStdioHandles\000\377", (void*)primitiveFileStdioHandles},
	{(void*)_m, "primitiveFileSync\000\001", (void*)primitiveFileSync},
	{(void*)_m, "primitiveFileTruncate\000\001", (void*)primitiveFileTruncate},
	{(void*)_m, "primitiveFileWrite\000\001", (void*)primitiveFileWrite},
	{(void*)_m, "primitiveHasFileAccess\000\377", (void*)primitiveHasFileAccess},
	{(void*)_m, "setInterpreter", (void*)setInterpreter},
	{(void*)_m, "setMacFileTypeAndCreator", (void*)setMacFileTypeAndCreator},
	{(void*)_m, "shutdownModule\000\377", (void*)shutdownModule},
	{NULL, NULL, NULL}
};

#else /* ifdef SQ_BUILTIN_PLUGIN */

signed char primitiveConnectToFileAccessorDepth = 1;
signed char primitiveConnectToFileDescriptorAccessorDepth = 0;
signed char primitiveDirectoryCreateAccessorDepth = 1;
signed char primitiveDirectoryDeleteAccessorDepth = 1;
signed char primitiveDirectoryEntryAccessorDepth = 1;
signed char primitiveDirectoryGetMacTypeAndCreatorAccessorDepth = 1;
signed char primitiveDirectoryLookupAccessorDepth = 1;
signed char primitiveDirectorySetMacTypeAndCreatorAccessorDepth = 1;
signed char primitiveFileAtEndAccessorDepth = 1;
signed char primitiveFileCloseAccessorDepth = 1;
signed char primitiveFileDeleteAccessorDepth = 1;
signed char primitiveFileDescriptorTypeAccessorDepth = 0;
signed char primitiveFileFlushAccessorDepth = 1;
signed char primitiveFileGetPositionAccessorDepth = 1;
signed char primitiveFileOpenAccessorDepth = 2;
signed char primitiveFileOpenNewAccessorDepth = 2;
signed char primitiveFileReadAccessorDepth = 1;
signed char primitiveFileRenameAccessorDepth = 1;
signed char primitiveFileSetPositionAccessorDepth = 1;
signed char primitiveFileSizeAccessorDepth = 1;
signed char primitiveFileSyncAccessorDepth = 1;
signed char primitiveFileTruncateAccessorDepth = 1;
signed char primitiveFileWriteAccessorDepth = 1;

#endif /* ifdef SQ_BUILTIN_PLUGIN */
