/* $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); }