home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Micro R&D 1
/
MicroRD-CD-ROM-Vol1-1994.iso
/
disktools
/
misc
/
flat1_3.lzh
/
flat
/
Flat-Handler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-26
|
38KB
|
1,518 lines
/* $Revision Header * Header built automatically - do not edit! *************
*
* (C) Copyright 1991 by Olaf Barthel
*
* Name .....: Flat-Handler.c
* Created ..: Saturday 11-May-91 17:55
* Revision .: 3
*
* Date Author Comment
* ========= ======== ====================
* 26-Jul-91 Olsen Added ACTION_COPY_DIR
* 11-Jul-91 Olsen Minor fixes.
* 11-May-91 Olsen Created this file!
*
* $Revision Header ********************************************************/
/* Standard FS error types. */
enum { ERR_WRITEPROTECT,ERR_NODISK,ERR_UNREADABLE,ERR_WRITEERROR };
/* This is a link node used both for locks and filehandles. */
struct FlatNode
{
struct FlatNode *fn_Succ; /* Vanilla node head. */
struct FlatNode *fn_Pred;
ULONG fn_UniqueID; /* A unique ID. */
LONG fn_Mode; /* Either shared or exclusive. */
struct DeviceNode *fn_DevInfo; /* Pointer to a device node,
* needed by ExNext and the like.
*/
ULONG fn_BlockSize; /* Size of a block (512 bytes are standard). */
ULONG fn_FirstBlock; /* The first accessible block. */
ULONG fn_NumBlocks; /* Maximum number of available blocks. */
LONG fn_Position; /* Current file position in bytes. */
struct FileLock fn_Lock; /* A dummy file lock. */
UBYTE fn_Name[40]; /* Name of this file. */
struct MsgPort *fn_DiskPort; /* Driver data. */
struct IOExtTD *fn_DiskRequest;
APTR fn_DiskBuffer;
BYTE fn_CheckCount; /* The disk state is checked
* every tenth r/w attempt,
* this byte keeps the count.
*/
};
/* This list keeps all the locks and filehandles. */
struct List FlatList;
/* Each open/lock call increments this counter to
* guarantee that each item receives a unique identifier.
*/
ULONG UniqueCounter = 0;
/* Shared library identifiers. */
struct ExecBase *SysBase = NULL;
struct DosLibrary *DOSBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
/* Prototypes for this module. */
LONG __saveds HandlerEntry(VOID);
LONG __regargs DoRead(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller);
LONG __regargs DoWrite(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller);
UBYTE * __regargs BaseName(UBYTE *String);
UBYTE __regargs Local2Upper(UBYTE c);
UBYTE __regargs StrCmp(UBYTE *a,UBYTE *b);
struct FlatNode * __regargs FindFlatNodeByID(ULONG UniqueID);
struct FlatNode * __regargs FindFlatNodeByName(UBYTE *Name);
VOID __regargs BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength);
LONG __regargs ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive);
struct DeviceNode * __regargs FindDevice(struct DeviceNode *LastNode,struct FileSysStartupMsg **Startup,struct DosEnvec **DosEnvec,UBYTE *Name);
VOID __regargs DeleteNode(struct FlatNode *FlatNode);
struct FlatNode * __regargs CreateNode(LONG Type,UBYTE *Name);
VOID __regargs ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc);
struct DosPacket * __regargs WaitPacket(struct Process *HandlerProc);
/* HandlerEntry():
*
* Entry point for this module.
*/
LONG __saveds
HandlerEntry()
{
struct Process *HandlerProc;
struct FileHandle *FileHandle;
struct FileLock *FileLock;
LONG ReadBytes,WriteBytes,Bytes;
LONG NewPosition;
struct FileInfoBlock *FileInfo;
UBYTE *FileName;
UBYTE NameBuffer[257];
struct DosPacket *FlatPacket;
struct DeviceNode *FlatDevNode;
struct FlatNode *FlatNode;
/* Set up SysBase. */
SysBase = *(struct ExecBase **)4;
/* Know who we are. */
HandlerProc = (struct Process *)SysBase -> ThisTask;
/* Started from Shell (oops!)? */
if(!HandlerProc -> pr_CLI)
{
/* Wait for startup packet. */
FlatPacket = WaitPacket(HandlerProc);
/* Clear the list. */
NewList(&FlatList);
/* Pick up the pointer to our DeviceNode. */
FlatDevNode = (struct DeviceNode *)BADDR(FlatPacket -> dp_Arg3);
/* Install ourselves at the other hand. */
FlatDevNode -> dn_Task = &HandlerProc -> pr_MsgPort;
/* Open DOS; we are not making DOS calls but
* rather use the base to scan for block-
* mapped devices.
*/
if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0)))
{
ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
goto FallOff;
}
/* Open Intuition; we might want to put up
* auto-requesters.
*/
if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
{
ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
goto FallOff;
}
/* Initialization finished, now return the
* startup packet.
*/
ReturnPacket(FlatPacket,DOSTRUE,FlatPacket -> dp_Res2,HandlerProc);
/* Go into loop waiting for data packets. */
FOREVER
{
/* Wait for packet. */
FlatPacket = WaitPacket(HandlerProc);
/* Examine the packet type. */
switch(FlatPacket -> dp_Type)
{
/* Obtain a filelock. */
case ACTION_LOCATE_OBJECT:
/* Convert the file name. */
BtoCStr(NameBuffer,FlatPacket -> dp_Arg2,256);
/* Are we to return a lock
* to a file or a lock to the
* root directory?
*/
if(FileName = BaseName(NameBuffer))
{
/* Look for a file of this name. */
if(FlatNode = FindFlatNodeByName(FileName))
{
/* See if the file is currently locked. */
if((FlatNode -> fn_Mode != FlatPacket -> dp_Arg3) || (FlatPacket -> dp_Arg3 == EXCLUSIVE_LOCK && FlatNode -> fn_Mode == EXCLUSIVE_LOCK))
{
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
break;
}
}
/* Create a new item and add it to the list. */
if(FlatNode = CreateNode(FlatPacket -> dp_Arg3,FileName))
{
AddTail(&FlatList,(struct Node *)FlatNode);
/* Initialize the default data so DOS will
* get along with us.
*/
FlatNode -> fn_Lock . fl_Access = FlatPacket -> dp_Arg3;
FlatNode -> fn_Lock . fl_Task = &HandlerProc -> pr_MsgPort;
FlatNode -> fn_Lock . fl_Volume = MKBADDR(FlatDevNode);
FlatNode -> fn_Lock . fl_Key = FlatNode -> fn_UniqueID;
FlatPacket -> dp_Res1 = MKBADDR(&FlatNode -> fn_Lock);
strcpy(FlatNode -> fn_Name,FileName);
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
}
else
{
if(FlatNode = CreateNode(FlatPacket -> dp_Arg3,NULL))
{
AddTail(&FlatList,(struct Node *)FlatNode);
FlatNode -> fn_Lock . fl_Access = FlatPacket -> dp_Arg3;
FlatNode -> fn_Lock . fl_Task = &HandlerProc -> pr_MsgPort;
FlatNode -> fn_Lock . fl_Volume = MKBADDR(FlatDevNode);
FlatNode -> fn_Lock . fl_Key = FlatNode -> fn_UniqueID;
FlatPacket -> dp_Res1 = MKBADDR(&FlatNode -> fn_Lock);
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
}
break;
/* Free a lock obtained above. */
case ACTION_FREE_LOCK:
/* Is the lock part of the list? */
if(FlatPacket -> dp_Arg1)
{
if(FlatNode = FindFlatNodeByID(((struct FileLock *)BADDR(FlatPacket -> dp_Arg1)) -> fl_Key))
{
Remove((struct Node *)FlatNode);
DeleteNode(FlatNode);
}
}
FlatPacket -> dp_Res1 = DOSTRUE;
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
break;
/* Duplicate a shared lock. */
case ACTION_COPY_DIR:
/* Make sure a ZERO lock gives
* a more or less valid return
* code.
*/
FlatPacket -> dp_Res1 = 0;
FlatPacket -> dp_Res2 = 0;
/* Are we to duplicate a non-ZERO lock? */
if(FlatPacket -> dp_Arg1)
{
FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
/* Try to find the corresponding list entry. */
if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
{
/* Only shared locks may be duplicated. */
if(FlatNode -> fn_Mode == EXCLUSIVE_LOCK)
{
FlatPacket -> dp_Res1 = DOSFALSE;
FlatPacket -> dp_Res2 = ERROR_OBJECT_IN_USE;
}
else
{
struct FlatNode *AnotherNode;
/* Create a new node. */
if(FlatNode -> fn_Name[0])
AnotherNode = CreateNode(SHARED_LOCK,FlatNode -> fn_Name);
else
AnotherNode = CreateNode(SHARED_LOCK,NULL);
/* Did we get what we wanted? */
if(AnotherNode)
{
/* Not quite so unique I suppose. */
AnotherNode -> fn_UniqueID = FlatNode -> fn_UniqueID;
/* Add the freshly created lock
* to the list.
*/
AddTail(&FlatList,(struct Node *)AnotherNode);
/* Fill in the Lock data. */
AnotherNode -> fn_Lock . fl_Access = SHARED_LOCK;
AnotherNode -> fn_Lock . fl_Task = &HandlerProc -> pr_MsgPort;
AnotherNode -> fn_Lock . fl_Volume = MKBADDR(FlatDevNode);
AnotherNode -> fn_Lock . fl_Key = AnotherNode -> fn_UniqueID;
/* Successful return. */
FlatPacket -> dp_Res1 = MKBADDR(&AnotherNode -> fn_Lock);
}
else
{
/* Failed to create node. */
FlatPacket -> dp_Res1 = DOSFALSE;
FlatPacket -> dp_Res2 = ERROR_NO_FREE_STORE;
}
}
}
else
{
/* Couldn't find the lock. */
FlatPacket -> dp_Res1 = DOSFALSE;
FlatPacket -> dp_Res2 = ERROR_OBJECT_NOT_FOUND;
}
}
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
break;
/* Examine a file. */
case ACTION_EXAMINE_OBJECT:
/* Get filelock and fileinfoblock in handy variables. */
FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2);
/* Are both identifiers valid? */
if(FileLock && FileInfo)
{
BYTE Success = FALSE;
/* Can we find the item? */
if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
{
struct FileSysStartupMsg *Startup;
struct DosEnvec *DosEnvec;
/* Is it a file or a directory? */
if(FlatNode -> fn_Name[0])
{
/* Find the approriate device. */
if(FlatNode -> fn_DevInfo = FindDevice(NULL,&Startup,&DosEnvec,FlatNode -> fn_Name))
{
struct MsgPort *DiskPort;
/* Create device driver data. */
if(DiskPort = (struct MsgPort *)CreatePort(NULL,0))
{
struct IOExtTD *DiskRequest;
if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
{
BtoCStr(NameBuffer,Startup -> fssm_Device,256);
if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
{
/* We are actually faking part of the data
* to be returned in the fileinfoblock.
* This isn't Unix and there are only two
* kinds of directory entries: files and
* directories. The protection bits are by
* default configured to mimic the state of
* the corresponding drive. If not write-
* enabled, the file will have the write
* access-bit cleared, if there is no disk
* in the drive, the read bit will be cleared,
* the file size will be zero as well.
*/
memset(FileInfo,0,sizeof(struct FileInfoBlock));
FileInfo -> fib_DiskKey = FileLock -> fl_Key;
FileInfo -> fib_DirEntryType = -3;
FileInfo -> fib_Protection = FIBF_EXECUTE|FIBF_DELETE;
FileInfo -> fib_Size = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
FileInfo -> fib_NumBlocks = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
/* The rest is mocked up or cleared
* with zeroes, a disk may not have
* a valid root block on it.
*/
DateStamp(&FileInfo -> fib_Date);
memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
if(!DoIO(DiskRequest))
{
if(DiskRequest -> iotd_Req . io_Actual)
FileInfo -> fib_Protection |= FIBF_WRITE;
}
DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
if(!DoIO(DiskRequest))
{
if(DiskRequest -> iotd_Req . io_Actual)
{
FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
}
}
Success = TRUE;
CloseDevice(DiskRequest);
}
DeleteExtIO(DiskRequest);
}
DeletePort(DiskPort);
}
}
}
else
{
/* This is very much the same as above,
* but this time it's the root directory
* we will create.
*/
memset(FileInfo,0,sizeof(struct FileInfoBlock));
FileInfo -> fib_DiskKey = FileLock -> fl_Key;
FileInfo -> fib_DirEntryType = 1;
FileInfo -> fib_Protection = FIBF_EXECUTE;
FileInfo -> fib_Size = 0;
FileInfo -> fib_NumBlocks = 0;
DateStamp(&FileInfo -> fib_Date);
strcpy(FileInfo -> fib_FileName,"\4FLAT");
Success = TRUE;
}
}
if(Success)
{
FlatPacket -> dp_Res1 = DOSTRUE;
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
break;
/* Examine the next directory entry (if available). */
case ACTION_EXAMINE_NEXT:
/* This works very much the same as above, with the
* exception that we are trying to gather information
* on the next available DosList Device entry.
*/
FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2);
if(FileLock && FileInfo)
{
BYTE Success = FALSE;
if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
{
struct FileSysStartupMsg *Startup;
struct DosEnvec *DosEnvec;
if(FlatNode -> fn_DevInfo = FindDevice(FlatNode -> fn_DevInfo,&Startup,&DosEnvec,NULL))
{
struct MsgPort *DiskPort;
if(DiskPort = (struct MsgPort *)CreatePort(NULL,0))
{
struct IOExtTD *DiskRequest;
if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
{
BtoCStr(NameBuffer,Startup -> fssm_Device,256);
if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
{
memset(FileInfo,0,sizeof(struct FileInfoBlock));
FileInfo -> fib_DiskKey = FileLock -> fl_Key;
FileInfo -> fib_DirEntryType = -1;
FileInfo -> fib_Protection = FIBF_EXECUTE|FIBF_DELETE;
FileInfo -> fib_Size = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
FileInfo -> fib_NumBlocks = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
DateStamp(&FileInfo -> fib_Date);
memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
if(!DoIO(DiskRequest))
{
if(DiskRequest -> iotd_Req . io_Actual)
FileInfo -> fib_Protection |= FIBF_WRITE;
}
DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
if(!DoIO(DiskRequest))
{
if(DiskRequest -> iotd_Req . io_Actual)
{
FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
}
}
Success = TRUE;
CloseDevice(DiskRequest);
}
DeleteExtIO(DiskRequest);
}
DeletePort(DiskPort);
}
}
else
{
ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_MORE_ENTRIES,HandlerProc);
break;
}
}
if(Success)
{
FlatPacket -> dp_Res1 = DOSTRUE;
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
break;
/* Open any file for reading/writing. */
case ACTION_FINDINPUT:
case ACTION_FINDOUTPUT:
case ACTION_FINDUPDATE:
/* Convert the file name. */
BtoCStr(NameBuffer,FlatPacket -> dp_Arg3,256);
if(FileName = BaseName(NameBuffer))
{
LONG Mode;
/* Only the MODE_OLDFILE type allows
* shared data access.
*/
if(FlatPacket -> dp_Type == ACTION_FINDINPUT)
Mode = SHARED_LOCK;
else
Mode = EXCLUSIVE_LOCK;
FileHandle = (struct FileHandle *)BADDR(FlatPacket -> dp_Arg1);
/* Is there already a lock or filehandle by this
* name?
*/
if(FlatNode = FindFlatNodeByName(FileName))
{
/* If so, is it locked? */
if((FlatNode -> fn_Mode != Mode) || (Mode == EXCLUSIVE_LOCK && FlatNode -> fn_Mode == EXCLUSIVE_LOCK))
{
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
break;
}
}
/* Create a new list entry. */
if(FlatNode = CreateNode(Mode,FileName))
{
AddTail(&FlatList,(struct Node *)FlatNode);
FileHandle -> fh_Arg1 = FlatNode -> fn_UniqueID;
/* Turn on the disk motor. */
FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_MOTOR;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Length = 1;
DoIO(FlatNode -> fn_DiskRequest);
ReturnPacket(FlatPacket,DOSTRUE,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_FREE_STORE,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
break;
/* Close a file opened above. */
case ACTION_END:
/* Find the node. */
if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
{
/* Turn off the motor. */
FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_MOTOR;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Length = 0;
DoIO(FlatNode -> fn_DiskRequest);
Remove((struct Node *)FlatNode);
DeleteNode(FlatNode);
}
ReturnPacket(FlatPacket,DOSTRUE,0,HandlerProc);
break;
/* Read a couple of bytes from a file. */
case ACTION_READ:
/* Do we have a valid filehandle? */
if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
{
ReadBytes = FlatPacket -> dp_Arg3;
/* Reading across the data media size? */
if(FlatNode -> fn_Position + ReadBytes > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
ReadBytes = -1;
FlatPacket -> dp_Res2 = 0;
/* Read a few bytes. */
if(ReadBytes > 0)
{
if(Bytes = DoRead(FlatNode,ReadBytes,(APTR)FlatPacket -> dp_Arg2,FlatPacket -> dp_Port -> mp_SigTask))
FlatNode -> fn_Position += Bytes;
FlatPacket -> dp_Res1 = Bytes;
}
else
{
if(ReadBytes == 0)
FlatPacket -> dp_Res1 = 0;
else
FlatPacket -> dp_Res1 = -1;
}
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
break;
/* Write a few bytes to a file. */
case ACTION_WRITE:
if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
{
WriteBytes = FlatPacket -> dp_Arg3;
if(FlatNode -> fn_Position + WriteBytes > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
WriteBytes = -1;
FlatPacket -> dp_Res2 = 0;
if(WriteBytes > 0)
{
if(Bytes = DoWrite(FlatNode,WriteBytes,(APTR)FlatPacket -> dp_Arg2,FlatPacket -> dp_Port -> mp_SigTask))
FlatNode -> fn_Position += Bytes;
FlatPacket -> dp_Res1 = Bytes;
}
else
{
if(WriteBytes == 0)
FlatPacket -> dp_Res1 = 0;
else
FlatPacket -> dp_Res1 = -1;
}
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
break;
/* Move the r/w pointer inside a file. */
case ACTION_SEEK:
if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
{
if(FlatPacket -> dp_Arg3 == OFFSET_BEGINNING)
NewPosition = FlatPacket -> dp_Arg2;
if(FlatPacket -> dp_Arg3 == OFFSET_CURRENT)
NewPosition = FlatNode -> fn_Position + FlatPacket -> dp_Arg2;
if(FlatPacket -> dp_Arg3 == OFFSET_END)
NewPosition = FlatNode -> fn_Position - FlatPacket -> dp_Arg2;
if(NewPosition < 0 || NewPosition > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
{
FlatPacket -> dp_Res1 = -1;
FlatPacket -> dp_Res2 = ERROR_SEEK_ERROR;
}
else
{
FlatPacket -> dp_Res1 = FlatNode -> fn_Position;
FlatNode -> fn_Position = NewPosition;
}
ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
break;
/* Remove the handler. */
case ACTION_DIE:
/* Are we allowed to remove ourselves? */
if(!FlatList . lh_Head -> ln_Succ)
{
ReturnPacket(FlatPacket,DOSTRUE,0,HandlerProc);
goto FallOff;
}
else
ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
break;
/* Ignore the rest of the packets. */
default:
ReturnPacket(FlatPacket,DOSFALSE,ERROR_ACTION_NOT_KNOWN,HandlerProc);
break;
}
}
/* Cease actions, close libraries and exit. */
FallOff: FlatDevNode -> dn_Task = NULL;
if(IntuitionBase)
CloseLibrary(IntuitionBase);
if(DOSBase)
CloseLibrary(DOSBase);
}
}
/* BaseName(UBYTE *String):
*
* Returns the base of a filename.
*/
UBYTE * __regargs
BaseName(UBYTE *String)
{
if(String[0])
{
SHORT i;
for(i = strlen(String) - 1 ; i >= 0 ; i--)
{
if(String[i] == ':' || String[i] == '/')
{
if(String[i + 1])
return(&String[i + 1]);
else
return(NULL);
}
}
return(String);
}
else
return(NULL);
}
/* Local2Upper(UBYTE c):
*
* Convert a character to upper case.
*/
UBYTE __regargs
Local2Upper(UBYTE c)
{
return((UBYTE)((((c) >= 224 && (c) <= 254) || ((c) >= 'a' && (c) <= 'z')) ? (c) - 32 : c));
}
/* StrCmp(UBYTE *a,UBYTE *b):
*
* Do string comparison ignoring case.
*/
UBYTE __regargs
StrCmp(UBYTE *a,UBYTE *b)
{
for( ; Local2Upper(*a) == Local2Upper(*b) ; a++, b++)
{
if(!(*a))
return(0);
}
return((UBYTE)(Local2Upper(*a) - Local2Upper(*b)));
}
/* FindFlatNodeByID(ULONG UniqueID):
*
* Scan the item list looking for a list entry with
* a matching ID.
*/
struct FlatNode * __regargs
FindFlatNodeByID(ULONG UniqueID)
{
struct FlatNode *Node;
Node = (struct FlatNode *)FlatList . lh_Head;
while(Node -> fn_Succ)
{
if(Node -> fn_UniqueID == UniqueID)
return(Node);
Node = Node -> fn_Succ;
}
return(NULL);
}
/* FindFlatNodeByName(UBYTE *Name):
*
* Scan the item list looking for an entry with a
* matching name.
*/
struct FlatNode * __regargs
FindFlatNodeByName(UBYTE *Name)
{
struct FlatNode *Node;
Node = (struct FlatNode *)FlatList . lh_Head;
while(Node -> fn_Succ)
{
if(!StrCmp(Node -> fn_Name,Name))
return(Node);
Node = Node -> fn_Succ;
}
return(NULL);
}
/* BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength):
*
* Convert a BCPL string into a `C' string.
*/
VOID __regargs
BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength)
{
UBYTE *Src,Length;
if(Src = (UBYTE *)BADDR(String))
{
if((Length = Src[0]) > MaxLength)
Length = MaxLength;
Src++;
while(Length--)
*Name++ = *Src++;
*Name = 0;
}
}
/* ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive):
*
* If trouble shows up, behave like the standard
* FS and complain.
*/
LONG __regargs
ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive)
{
STATIC struct IntuiText DiskWriteProtected[3] =
{
{0,1,JAM2,15, 5,NULL,"Disk in drive", &DiskWriteProtected[1]},
{0,1,JAM2,15,15,NULL,"################################", &DiskWriteProtected[2]},
{0,1,JAM2,15,25,NULL,"is write protected", NULL}
};
STATIC struct IntuiText DiskNotPresent[2] =
{
{0,1,JAM2,15, 5,NULL,"No disk present in drive", &DiskNotPresent[1]},
{0,1,JAM2,15,15,NULL,"################################", NULL}
};
STATIC struct IntuiText DiskUnreadable[3] =
{
{0,1,JAM2,15, 5,NULL,"Disk in drive", &DiskUnreadable[1]},
{0,1,JAM2,15,15,NULL,"################################", &DiskUnreadable[2]},
{0,1,JAM2,15,25,NULL,"is unreadable", NULL}
};
STATIC struct IntuiText DiskWriteError[2] =
{
{0,1,JAM2,15, 5,NULL,"Error writing to drive", &DiskWriteError[1]},
{0,1,JAM2,15,15,NULL,"################################", NULL}
};
STATIC struct IntuiText Retry =
{
0,1,JAM2,7,3,NULL,"Retry",NULL
};
STATIC struct IntuiText Cancel =
{
0,1,JAM2,7,3,NULL,"Cancel",NULL
};
/* A -1 will result in cancelling the
* requester.
*/
if(WindowPtr != (APTR)-1)
{
struct IntuiText *BodyText;
SHORT i;
/* Install the right alert type. */
switch(Type)
{
case ERR_WRITEPROTECT: BodyText = DiskWriteProtected;
break;
case ERR_NODISK: BodyText = DiskNotPresent;
break;
case ERR_UNREADABLE: BodyText = DiskUnreadable;
break;
case ERR_WRITEERROR: BodyText = DiskWriteError;
break;
}
/* Add the drive name. */
for(i = 0 ; BodyText[1] . IText[i] = Local2Upper(Drive[i + 1]) ; i++);
/* Show the requester. */
return((LONG)AutoRequest(WindowPtr,BodyText,&Retry,&Cancel,DISKINSERTED,NULL,320,72));
}
return(FALSE);
}
/* FindDevice():
*
* Find a DeviceNode entry in the DosList.
*/
struct DeviceNode * __regargs
FindDevice(struct DeviceNode *LastNode,struct FileSysStartupMsg **Startup,struct DosEnvec **DosEnvec,UBYTE *Name)
{
struct DeviceNode *DevInfo;
STATIC UBYTE NameBuffer[257];
Forbid();
if(LastNode)
DevInfo = (struct DeviceNode *)BADDR(LastNode -> dn_Next);
else
DevInfo = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info)) -> di_DevInfo);
while(DevInfo)
{
if(DevInfo -> dn_Type == DLT_DEVICE && DevInfo -> dn_Task && DevInfo -> dn_Startup)
{
if(Name)
{
BtoCStr(NameBuffer,DevInfo -> dn_Name,256);
if(!StrCmp(NameBuffer,Name))
{
if(Startup)
*Startup = (struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup);
if(DosEnvec)
*DosEnvec = (struct DosEnvec *)BADDR(((struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup)) -> fssm_Environ);
Permit();
return(DevInfo);
}
}
else
{
if(Startup)
*Startup = (struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup);
if(DosEnvec)
*DosEnvec = (struct DosEnvec *)BADDR(((struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup)) -> fssm_Environ);
Permit();
return(DevInfo);
}
}
DevInfo = (struct DeviceNode *)BADDR(DevInfo -> dn_Next);
}
Permit();
return(NULL);
}
/* DeleteNode(struct FlatNode *FlatNode):
*
* Delete a freshly created item node freeing
* all associated resources.
*/
VOID __regargs
DeleteNode(struct FlatNode *FlatNode)
{
if(FlatNode -> fn_DiskBuffer)
FreeMem(FlatNode -> fn_DiskBuffer,FlatNode -> fn_BlockSize);
if(FlatNode -> fn_DiskRequest)
{
if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Device)
CloseDevice(FlatNode -> fn_DiskRequest);
DeleteExtIO(FlatNode -> fn_DiskRequest);
}
if(FlatNode -> fn_DiskPort)
DeletePort(FlatNode -> fn_DiskPort);
FreeMem(FlatNode,sizeof(struct FlatNode));
}
/* CreateNode(LONG Type,UBYTE *Name):
*
* Create an item node with given characteristics,
* can be either shared or exclusive access, if a name
* is given will open the approriate device driver.
*/
struct FlatNode * __regargs
CreateNode(LONG Type,UBYTE *Name)
{
struct FlatNode *FlatNode;
if(FlatNode = (struct FlatNode *)AllocMem(sizeof(struct FlatNode),MEMF_PUBLIC|MEMF_CLEAR))
{
if(Name)
{
struct DeviceNode *DevInfo;
struct FileSysStartupMsg *Startup;
struct DosEnvec *DosEnvec;
/* Try to find the device. */
if(!(DevInfo = FindDevice(NULL,&Startup,&DosEnvec,Name)))
{
DeleteNode(FlatNode);
return(NULL);
}
/* Create a MsgPort, this is where a
* potential problem exists: since all
* MsgPorts refer to the handler process,
* we will run out of signal bits if
* more than app. 16 files/locks are open at
* the same time.
*/
if(!(FlatNode -> fn_DiskPort = (struct MsgPort *)CreatePort(NULL,0)))
{
DeleteNode(FlatNode);
return(NULL);
}
/* Create a device request. */
if(!(FlatNode -> fn_DiskRequest = (struct IOExtTD *)CreateExtIO(FlatNode -> fn_DiskPort,sizeof(struct IOExtTD))))
{
DeleteNode(FlatNode);
return(NULL);
}
/* Open the device driver. */
if(OpenDevice(&((UBYTE *)BADDR(Startup -> fssm_Device))[1],Startup -> fssm_Unit,FlatNode -> fn_DiskRequest,Startup -> fssm_Flags))
{
DeleteNode(FlatNode);
return(NULL);
}
/* Inquire the unit data. */
FlatNode -> fn_BlockSize = DosEnvec -> de_SizeBlock << 2;
FlatNode -> fn_FirstBlock = DosEnvec -> de_LowCyl * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
FlatNode -> fn_NumBlocks = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
/* Create a r/w buffer. */
if(!(FlatNode -> fn_DiskBuffer = (APTR)AllocMem(FlatNode -> fn_BlockSize,DosEnvec -> de_BufMemType)))
{
DeleteNode(FlatNode);
return(NULL);
}
strcpy(&FlatNode -> fn_Name[1],Name);
}
FlatNode -> fn_Mode = Type;
FlatNode -> fn_UniqueID = UniqueCounter++;
}
return(FlatNode);
}
/* ReturnPacket():
*
* Return a standard DOS packet to its sender.
*/
VOID __regargs
ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc)
{
struct MsgPort *ReplyPort;
ReplyPort = Packet -> dp_Port;
Packet -> dp_Res1 = Res1;
Packet -> dp_Res2 = Res2;
Packet -> dp_Port = &HandlerProc -> pr_MsgPort;
Packet -> dp_Link -> mn_Node . ln_Name = (APTR)Packet;
Packet -> dp_Link -> mn_Node . ln_Succ = NULL;
Packet -> dp_Link -> mn_Node . ln_Pred = NULL;
PutMsg(ReplyPort,Packet -> dp_Link);
}
/* WaitPacket(struct Process *HandlerProc):
*
* Wait for packet arrival.
*/
struct DosPacket * __regargs
WaitPacket(struct Process *HandlerProc)
{
struct Message *DOSMsg;
WaitPort(&HandlerProc -> pr_MsgPort);
DOSMsg = (struct Message *)GetMsg(&HandlerProc -> pr_MsgPort);
return((struct DosPacket *)DOSMsg -> mn_Node . ln_Name);
}
/* DoRead():
*
* Read a few bytes from a file.
*/
LONG __regargs
DoRead(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller)
{
LONG Block,Length,BytesRead = 0,Offset = FlatNode -> fn_Position;
UBYTE *DiskBuffer = FlatNode -> fn_DiskBuffer;
/* Time for a check? */
if(!FlatNode -> fn_CheckCount)
{
FOREVER
{
FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
/* Is there still a disk in the drive? */
if(!DoIO(FlatNode -> fn_DiskRequest))
{
if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
{
if(!ShowRequest(Caller -> pr_WindowPtr,ERR_NODISK,FlatNode -> fn_Name))
return(0);
}
else
break;
}
}
}
if(FlatNode -> fn_CheckCount++ == 10)
FlatNode -> fn_CheckCount = 0;
/* Convert offset from bytes into blocks. */
Block = Offset / FlatNode -> fn_BlockSize;
Offset = Offset % FlatNode -> fn_BlockSize;
if(Size > 0)
{
/* Read the data block by block... */
while(Size > 0)
{
Retry: FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = CMD_READ;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Length = FlatNode -> fn_BlockSize;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Data = DiskBuffer;
/* Read the block. */
if(DoIO(FlatNode -> fn_DiskRequest))
{
if(ShowRequest(Caller -> pr_WindowPtr,ERR_UNREADABLE,FlatNode -> fn_Name))
goto Retry;
else
return(BytesRead);
}
Length = FlatNode -> fn_BlockSize - Offset;
if(Length > Size)
Length = Size;
/* Copy the data. */
memcpy(Buffer,&DiskBuffer[Offset],Length);
Buffer = &Buffer[Length];
Size -= Length;
BytesRead += Length;
Block++;
Offset = 0;
}
}
return(BytesRead);
}
/* DoWrite():
*
* Write a few bytes to a file.
*/
LONG __regargs
DoWrite(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller)
{
LONG Block,Length,BytesWritten = 0,Offset = FlatNode -> fn_Position;
UBYTE *DiskBuffer = FlatNode -> fn_DiskBuffer;
/* Time for a check? */
if(!FlatNode -> fn_CheckCount)
{
FOREVER
{
FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
/* Is there a disk in the drive? */
if(!DoIO(FlatNode -> fn_DiskRequest))
{
if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
{
if(!ShowRequest(Caller -> pr_WindowPtr,ERR_NODISK,FlatNode -> fn_Name))
return(0);
}
else
break;
}
}
FOREVER
{
FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
/* Is the disk write enabled? */
if(!DoIO(FlatNode -> fn_DiskRequest))
{
if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
{
if(!ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEPROTECT,FlatNode -> fn_Name))
return(0);
}
else
break;
}
}
}
if(FlatNode -> fn_CheckCount++ == 10)
FlatNode -> fn_CheckCount = 0;
/* Convert offset from bytes into blocks. */
Block = Offset / FlatNode -> fn_BlockSize;
Offset = Offset % FlatNode -> fn_BlockSize;
if(Size > 0)
{
while(Size > 0)
{
Retry1: if(Offset)
{
/* The data to write is smaller
* than a block, so we'll have to
* read the block to write to first,
* copy the data over and write the
* block back.
*/
FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = CMD_READ;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Length = FlatNode -> fn_BlockSize;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Data = DiskBuffer;
if(DoIO(FlatNode -> fn_DiskRequest))
{
if(ShowRequest(Caller -> pr_WindowPtr,ERR_UNREADABLE,FlatNode -> fn_Name))
goto Retry1;
else
return(BytesWritten);
}
Length = FlatNode -> fn_BlockSize - Offset;
if(Length > Size)
Length = Size;
memcpy(&DiskBuffer[Offset],Buffer,Length);
Retry2: FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = CMD_WRITE;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Length = FlatNode -> fn_BlockSize;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Data = DiskBuffer;
if(DoIO(FlatNode -> fn_DiskRequest))
{
if(ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEERROR,FlatNode -> fn_Name))
goto Retry2;
else
return(BytesWritten);
}
Buffer = &Buffer[Length];
Size -= Length;
BytesWritten += Length;
Block++;
Offset = 0;
}
else
{
if(Size > FlatNode -> fn_BlockSize)
Length = FlatNode -> fn_BlockSize;
else
{
if(Size < FlatNode -> fn_BlockSize)
memset(DiskBuffer,0,FlatNode -> fn_BlockSize);
Length = Size;
}
memcpy(DiskBuffer,Buffer,Length);
Retry3: FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = CMD_WRITE;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Length = FlatNode -> fn_BlockSize;
FlatNode -> fn_DiskRequest -> iotd_Req . io_Data = DiskBuffer;
if(DoIO(FlatNode -> fn_DiskRequest))
{
if(ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEERROR,FlatNode -> fn_Name))
goto Retry1;
else
return(BytesWritten);
}
Buffer = &Buffer[Length];
Size -= Length;
BytesWritten += Length;
Block++;
}
}
}
return(BytesWritten);
}