home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / disks / misc / flat / flat-handler.c < prev    next >
C/C++ Source or Header  |  1981-06-29  |  38KB  |  1,518 lines

  1. /* $Revision Header * Header built automatically - do not edit! *************
  2.  *
  3.  *    (C) Copyright 1991 by Olaf Barthel
  4.  *
  5.  *    Name .....:    Flat-Handler.c
  6.  *    Created ..:    Saturday 11-May-91 17:55
  7.  *    Revision .:    3
  8.  *
  9.  *    Date        Author        Comment
  10.  *    =========    ========    ====================
  11.  *    26-Jul-91    Olsen        Added ACTION_COPY_DIR
  12.  *    11-Jul-91    Olsen        Minor fixes.
  13.  *    11-May-91    Olsen        Created this file!
  14.  *
  15.  * $Revision Header ********************************************************/
  16.  
  17.     /* Standard FS error types. */
  18.  
  19. enum    { ERR_WRITEPROTECT,ERR_NODISK,ERR_UNREADABLE,ERR_WRITEERROR };
  20.  
  21.     /* This is a link node used both for locks and filehandles. */
  22.  
  23. struct FlatNode
  24. {
  25.     struct FlatNode        *fn_Succ;    /* Vanilla node head. */
  26.     struct FlatNode        *fn_Pred;
  27.  
  28.     ULONG             fn_UniqueID;    /* A unique ID. */
  29.  
  30.     LONG             fn_Mode;    /* Either shared or exclusive. */
  31.  
  32.     struct DeviceNode    *fn_DevInfo;    /* Pointer to a device node,
  33.                          * needed by ExNext and the like.
  34.                          */
  35.     ULONG             fn_BlockSize;    /* Size of a block (512 bytes are standard). */
  36.     ULONG             fn_FirstBlock;    /* The first accessible block. */
  37.     ULONG             fn_NumBlocks;    /* Maximum number of available blocks. */
  38.  
  39.     LONG             fn_Position;    /* Current file position in bytes. */
  40.     struct FileLock         fn_Lock;    /* A dummy file lock. */
  41.  
  42.     UBYTE             fn_Name[40];    /* Name of this file. */
  43.  
  44.     struct MsgPort        *fn_DiskPort;    /* Driver data. */
  45.     struct IOExtTD        *fn_DiskRequest;
  46.     APTR             fn_DiskBuffer;
  47.  
  48.     BYTE             fn_CheckCount;    /* The disk state is checked
  49.                          * every tenth r/w attempt,
  50.                          * this byte keeps the count.
  51.                          */
  52. };
  53.  
  54.     /* This list keeps all the locks and filehandles. */
  55.  
  56. struct List             FlatList;
  57.  
  58.     /* Each open/lock call increments this counter to
  59.      * guarantee that each item receives a unique identifier.
  60.      */
  61.  
  62. ULONG                 UniqueCounter = 0;
  63.  
  64.     /* Shared library identifiers. */
  65.  
  66. struct ExecBase            *SysBase = NULL;
  67. struct DosLibrary        *DOSBase = NULL;
  68. struct IntuitionBase        *IntuitionBase = NULL;
  69.  
  70.     /* Prototypes for this module. */
  71.  
  72. LONG __saveds            HandlerEntry(VOID);
  73.  
  74. LONG __regargs            DoRead(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller);
  75. LONG __regargs            DoWrite(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller);
  76.  
  77. UBYTE * __regargs        BaseName(UBYTE *String);
  78.  
  79. UBYTE __regargs            Local2Upper(UBYTE c);
  80. UBYTE __regargs            StrCmp(UBYTE *a,UBYTE *b);
  81.  
  82. struct FlatNode * __regargs    FindFlatNodeByID(ULONG UniqueID);
  83. struct FlatNode * __regargs    FindFlatNodeByName(UBYTE *Name);
  84.  
  85. VOID __regargs            BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength);
  86.  
  87. LONG __regargs            ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive);
  88.  
  89. struct DeviceNode * __regargs    FindDevice(struct DeviceNode *LastNode,struct FileSysStartupMsg    **Startup,struct DosEnvec **DosEnvec,UBYTE *Name);
  90.  
  91. VOID __regargs            DeleteNode(struct FlatNode *FlatNode);
  92. struct FlatNode * __regargs    CreateNode(LONG Type,UBYTE *Name);
  93.  
  94. VOID __regargs            ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc);
  95. struct DosPacket * __regargs    WaitPacket(struct Process *HandlerProc);
  96.  
  97.     /* HandlerEntry():
  98.      *
  99.      *    Entry point for this module.
  100.      */
  101.  
  102. LONG __saveds
  103. HandlerEntry()
  104. {
  105.     struct Process            *HandlerProc;
  106.  
  107.     struct FileHandle        *FileHandle;
  108.     struct FileLock            *FileLock;
  109.  
  110.     LONG                 ReadBytes,WriteBytes,Bytes;
  111.     LONG                 NewPosition;
  112.     struct FileInfoBlock        *FileInfo;
  113.     UBYTE                *FileName;
  114.     UBYTE                 NameBuffer[257];
  115.  
  116.     struct DosPacket        *FlatPacket;
  117.     struct DeviceNode        *FlatDevNode;
  118.  
  119.     struct FlatNode            *FlatNode;
  120.  
  121.         /* Set up SysBase. */
  122.  
  123.     SysBase = *(struct ExecBase **)4;
  124.  
  125.         /* Know who we are. */
  126.  
  127.     HandlerProc = (struct Process *)SysBase -> ThisTask;
  128.  
  129.         /* Started from Shell (oops!)? */
  130.  
  131.     if(!HandlerProc -> pr_CLI)
  132.     {
  133.             /* Wait for startup packet. */
  134.  
  135.         FlatPacket = WaitPacket(HandlerProc);
  136.  
  137.             /* Clear the list. */
  138.  
  139.         NewList(&FlatList);
  140.  
  141.             /* Pick up the pointer to our DeviceNode. */
  142.  
  143.         FlatDevNode = (struct DeviceNode *)BADDR(FlatPacket -> dp_Arg3);
  144.  
  145.             /* Install ourselves at the other hand. */
  146.  
  147.         FlatDevNode -> dn_Task = &HandlerProc -> pr_MsgPort;
  148.  
  149.             /* Open DOS; we are not making DOS calls but
  150.              * rather use the base to scan for block-
  151.              * mapped devices.
  152.              */
  153.  
  154.         if(!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0)))
  155.         {
  156.             ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
  157.             goto FallOff;
  158.         }
  159.  
  160.             /* Open Intuition; we might want to put up
  161.              * auto-requesters.
  162.              */
  163.  
  164.         if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
  165.         {
  166.             ReturnPacket(FlatPacket,DOSFALSE,FlatPacket -> dp_Res2,HandlerProc);
  167.             goto FallOff;
  168.         }
  169.  
  170.             /* Initialization finished, now return the
  171.              * startup packet.
  172.              */
  173.  
  174.         ReturnPacket(FlatPacket,DOSTRUE,FlatPacket -> dp_Res2,HandlerProc);
  175.  
  176.             /* Go into loop waiting for data packets. */
  177.  
  178.         FOREVER
  179.         {
  180.                 /* Wait for packet. */
  181.  
  182.             FlatPacket = WaitPacket(HandlerProc);
  183.  
  184.                 /* Examine the packet type. */
  185.  
  186.             switch(FlatPacket -> dp_Type)
  187.             {
  188.                     /* Obtain a filelock. */
  189.  
  190.                 case ACTION_LOCATE_OBJECT:
  191.  
  192.                         /* Convert the file name. */
  193.  
  194.                     BtoCStr(NameBuffer,FlatPacket -> dp_Arg2,256);
  195.  
  196.                         /* Are we to return a lock
  197.                          * to a file or a lock to the
  198.                          * root directory?
  199.                          */
  200.  
  201.                     if(FileName = BaseName(NameBuffer))
  202.                     {
  203.                             /* Look for a file of this name. */
  204.  
  205.                         if(FlatNode = FindFlatNodeByName(FileName))
  206.                         {
  207.                                 /* See if the file is currently locked. */
  208.  
  209.                             if((FlatNode -> fn_Mode != FlatPacket -> dp_Arg3) || (FlatPacket -> dp_Arg3 == EXCLUSIVE_LOCK && FlatNode -> fn_Mode == EXCLUSIVE_LOCK))
  210.                             {
  211.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  212.                                 break;
  213.                             }
  214.                         }
  215.  
  216.                             /* Create a new item and add it to the list. */
  217.  
  218.                         if(FlatNode = CreateNode(FlatPacket -> dp_Arg3,FileName))
  219.                         {
  220.                             AddTail(&FlatList,(struct Node *)FlatNode);
  221.  
  222.                                 /* Initialize the default data so DOS will
  223.                                  * get along with us.
  224.                                  */
  225.  
  226.                             FlatNode -> fn_Lock . fl_Access    = FlatPacket -> dp_Arg3;
  227.                             FlatNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  228.                             FlatNode -> fn_Lock . fl_Volume    = MKBADDR(FlatDevNode);
  229.                             FlatNode -> fn_Lock . fl_Key    = FlatNode -> fn_UniqueID;
  230.  
  231.                             FlatPacket -> dp_Res1 = MKBADDR(&FlatNode -> fn_Lock);
  232.  
  233.                             strcpy(FlatNode -> fn_Name,FileName);
  234.  
  235.                             ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  236.                         }
  237.                         else
  238.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  239.                     }
  240.                     else
  241.                     {
  242.                         if(FlatNode = CreateNode(FlatPacket -> dp_Arg3,NULL))
  243.                         {
  244.                             AddTail(&FlatList,(struct Node *)FlatNode);
  245.  
  246.                             FlatNode -> fn_Lock . fl_Access    = FlatPacket -> dp_Arg3;
  247.                             FlatNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  248.                             FlatNode -> fn_Lock . fl_Volume    = MKBADDR(FlatDevNode);
  249.                             FlatNode -> fn_Lock . fl_Key    = FlatNode -> fn_UniqueID;
  250.  
  251.                             FlatPacket -> dp_Res1 = MKBADDR(&FlatNode -> fn_Lock);
  252.  
  253.                             ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  254.                         }
  255.                         else
  256.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  257.                     }
  258.  
  259.                     break;
  260.  
  261.                     /* Free a lock obtained above. */
  262.  
  263.                 case ACTION_FREE_LOCK:
  264.  
  265.                         /* Is the lock part of the list? */
  266.  
  267.                     if(FlatPacket -> dp_Arg1)
  268.                     {
  269.                         if(FlatNode = FindFlatNodeByID(((struct FileLock *)BADDR(FlatPacket -> dp_Arg1)) -> fl_Key))
  270.                         {
  271.                             Remove((struct Node *)FlatNode);
  272.  
  273.                             DeleteNode(FlatNode);
  274.                         }
  275.                     }
  276.  
  277.                     FlatPacket -> dp_Res1 = DOSTRUE;
  278.  
  279.                     ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  280.  
  281.                     break;
  282.  
  283.                     /* Duplicate a shared lock. */
  284.  
  285.                 case ACTION_COPY_DIR:
  286.  
  287.                         /* Make sure a ZERO lock gives
  288.                          * a more or less valid return
  289.                          * code.
  290.                          */
  291.  
  292.                     FlatPacket -> dp_Res1 = 0;
  293.                     FlatPacket -> dp_Res2 = 0;
  294.  
  295.                         /* Are we to duplicate a non-ZERO lock? */
  296.  
  297.                     if(FlatPacket -> dp_Arg1)
  298.                     {
  299.                         FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
  300.  
  301.                             /* Try to find the corresponding list entry. */
  302.  
  303.                         if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
  304.                         {
  305.                                 /* Only shared locks may be duplicated. */
  306.  
  307.                             if(FlatNode -> fn_Mode == EXCLUSIVE_LOCK)
  308.                             {
  309.                                 FlatPacket -> dp_Res1 = DOSFALSE;
  310.                                 FlatPacket -> dp_Res2 = ERROR_OBJECT_IN_USE;
  311.                             }
  312.                             else
  313.                             {
  314.                                 struct FlatNode *AnotherNode;
  315.  
  316.                                     /* Create a new node. */
  317.  
  318.                                 if(FlatNode -> fn_Name[0])
  319.                                     AnotherNode = CreateNode(SHARED_LOCK,FlatNode -> fn_Name);
  320.                                 else
  321.                                     AnotherNode = CreateNode(SHARED_LOCK,NULL);
  322.  
  323.                                     /* Did we get what we wanted? */
  324.  
  325.                                 if(AnotherNode)
  326.                                 {
  327.                                         /* Not quite so unique I suppose. */
  328.  
  329.                                     AnotherNode -> fn_UniqueID = FlatNode -> fn_UniqueID;
  330.  
  331.                                         /* Add the freshly created lock
  332.                                          * to the list.
  333.                                          */
  334.  
  335.                                     AddTail(&FlatList,(struct Node *)AnotherNode);
  336.  
  337.                                         /* Fill in the Lock data. */
  338.  
  339.                                     AnotherNode -> fn_Lock . fl_Access    = SHARED_LOCK;
  340.                                     AnotherNode -> fn_Lock . fl_Task    = &HandlerProc -> pr_MsgPort;
  341.                                     AnotherNode -> fn_Lock . fl_Volume    = MKBADDR(FlatDevNode);
  342.                                     AnotherNode -> fn_Lock . fl_Key        = AnotherNode -> fn_UniqueID;
  343.  
  344.                                         /* Successful return. */
  345.  
  346.                                     FlatPacket -> dp_Res1 = MKBADDR(&AnotherNode -> fn_Lock);
  347.                                 }
  348.                                 else
  349.                                 {
  350.                                         /* Failed to create node. */
  351.  
  352.                                     FlatPacket -> dp_Res1 = DOSFALSE;
  353.                                     FlatPacket -> dp_Res2 = ERROR_NO_FREE_STORE;
  354.                                 }
  355.                             }
  356.                         }
  357.                         else
  358.                         {
  359.                                 /* Couldn't find the lock. */
  360.  
  361.                             FlatPacket -> dp_Res1 = DOSFALSE;
  362.                             FlatPacket -> dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  363.                         }
  364.                     }
  365.  
  366.                     ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  367.  
  368.                     break;
  369.  
  370.                     /* Examine a file. */
  371.  
  372.                 case ACTION_EXAMINE_OBJECT:
  373.  
  374.                         /* Get filelock and fileinfoblock in handy variables. */
  375.  
  376.                     FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
  377.                     FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2);
  378.  
  379.                         /* Are both identifiers valid? */
  380.  
  381.                     if(FileLock && FileInfo)
  382.                     {
  383.                         BYTE Success = FALSE;
  384.  
  385.                             /* Can we find the item? */
  386.  
  387.                         if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
  388.                         {
  389.                             struct FileSysStartupMsg    *Startup;
  390.                             struct DosEnvec            *DosEnvec;
  391.  
  392.                                 /* Is it a file or a directory? */
  393.  
  394.                             if(FlatNode -> fn_Name[0])
  395.                             {
  396.                                     /* Find the approriate device. */
  397.  
  398.                                 if(FlatNode -> fn_DevInfo = FindDevice(NULL,&Startup,&DosEnvec,FlatNode -> fn_Name))
  399.                                 {
  400.                                     struct MsgPort *DiskPort;
  401.  
  402.                                         /* Create device driver data. */
  403.  
  404.                                     if(DiskPort = (struct MsgPort *)CreatePort(NULL,0))
  405.                                     {
  406.                                         struct IOExtTD *DiskRequest;
  407.  
  408.                                         if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
  409.                                         {
  410.                                             BtoCStr(NameBuffer,Startup -> fssm_Device,256);
  411.  
  412.                                             if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
  413.                                             {
  414.                                                     /* We are actually faking part of the data
  415.                                                      * to be returned in the fileinfoblock.
  416.                                                      * This isn't Unix and there are only two
  417.                                                      * kinds of directory entries: files and
  418.                                                      * directories. The protection bits are by
  419.                                                      * default configured to mimic the state of
  420.                                                      * the corresponding drive. If not write-
  421.                                                      * enabled, the file will have the write
  422.                                                      * access-bit cleared, if there is no disk
  423.                                                      * in the drive, the read bit will be cleared,
  424.                                                      * the file size will be zero as well.
  425.                                                      */
  426.  
  427.                                                 memset(FileInfo,0,sizeof(struct FileInfoBlock));
  428.  
  429.                                                 FileInfo -> fib_DiskKey        = FileLock -> fl_Key;
  430.                                                 FileInfo -> fib_DirEntryType    = -3;
  431.                                                 FileInfo -> fib_Protection    = FIBF_EXECUTE|FIBF_DELETE;
  432.                                                 FileInfo -> fib_Size        = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
  433.                                                 FileInfo -> fib_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  434.  
  435.                                                     /* The rest is mocked up or cleared
  436.                                                      * with zeroes, a disk may not have
  437.                                                      * a valid root block on it.
  438.                                                      */
  439.  
  440.                                                 DateStamp(&FileInfo -> fib_Date);
  441.  
  442.                                                 memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
  443.  
  444.                                                 DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  445.  
  446.                                                 if(!DoIO(DiskRequest))
  447.                                                 {
  448.                                                     if(DiskRequest -> iotd_Req . io_Actual)
  449.                                                         FileInfo -> fib_Protection |= FIBF_WRITE;
  450.                                                 }
  451.  
  452.                                                 DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  453.  
  454.                                                 if(!DoIO(DiskRequest))
  455.                                                 {
  456.                                                     if(DiskRequest -> iotd_Req . io_Actual)
  457.                                                     {
  458.                                                         FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
  459.  
  460.                                                         FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
  461.                                                     }
  462.                                                 }
  463.  
  464.                                                 Success = TRUE;
  465.  
  466.                                                 CloseDevice(DiskRequest);
  467.                                             }
  468.  
  469.                                             DeleteExtIO(DiskRequest);
  470.                                         }
  471.  
  472.                                         DeletePort(DiskPort);
  473.                                     }
  474.                                 }
  475.                             }
  476.                             else
  477.                             {
  478.                                     /* This is very much the same as above,
  479.                                      * but this time it's the root directory
  480.                                      * we will create.
  481.                                      */
  482.  
  483.                                 memset(FileInfo,0,sizeof(struct FileInfoBlock));
  484.  
  485.                                 FileInfo -> fib_DiskKey        = FileLock -> fl_Key;
  486.                                 FileInfo -> fib_DirEntryType    = 1;
  487.                                 FileInfo -> fib_Protection    = FIBF_EXECUTE;
  488.                                 FileInfo -> fib_Size        = 0;
  489.                                 FileInfo -> fib_NumBlocks    = 0;
  490.  
  491.                                 DateStamp(&FileInfo -> fib_Date);
  492.  
  493.                                 strcpy(FileInfo -> fib_FileName,"\4FLAT");
  494.  
  495.                                 Success = TRUE;
  496.                             }
  497.                         }
  498.  
  499.                         if(Success)
  500.                         {
  501.                             FlatPacket -> dp_Res1 = DOSTRUE;
  502.  
  503.                             ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  504.                         }
  505.                         else
  506.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  507.                     }
  508.                     else
  509.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  510.  
  511.                     break;
  512.  
  513.                     /* Examine the next directory entry (if available). */
  514.  
  515.                 case ACTION_EXAMINE_NEXT:
  516.  
  517.                         /* This works very much the same as above, with the
  518.                          * exception that we are trying to gather information
  519.                          * on the next available DosList Device entry.
  520.                          */
  521.  
  522.                     FileLock = (struct FileLock *)BADDR(FlatPacket -> dp_Arg1);
  523.                     FileInfo = (struct FileInfoBlock *)BADDR(FlatPacket -> dp_Arg2);
  524.  
  525.                     if(FileLock && FileInfo)
  526.                     {
  527.                         BYTE Success = FALSE;
  528.  
  529.                         if(FlatNode = FindFlatNodeByID(FileLock -> fl_Key))
  530.                         {
  531.                             struct FileSysStartupMsg    *Startup;
  532.                             struct DosEnvec            *DosEnvec;
  533.  
  534.                             if(FlatNode -> fn_DevInfo = FindDevice(FlatNode -> fn_DevInfo,&Startup,&DosEnvec,NULL))
  535.                             {
  536.                                 struct MsgPort *DiskPort;
  537.  
  538.                                 if(DiskPort = (struct MsgPort *)CreatePort(NULL,0))
  539.                                 {
  540.                                     struct IOExtTD *DiskRequest;
  541.  
  542.                                     if(DiskRequest = (struct IOExtTD *)CreateExtIO(DiskPort,sizeof(struct IOExtTD)))
  543.                                     {
  544.                                         BtoCStr(NameBuffer,Startup -> fssm_Device,256);
  545.  
  546.                                         if(!OpenDevice(NameBuffer,Startup -> fssm_Unit,DiskRequest,Startup -> fssm_Flags))
  547.                                         {
  548.                                             memset(FileInfo,0,sizeof(struct FileInfoBlock));
  549.  
  550.                                             FileInfo -> fib_DiskKey        = FileLock -> fl_Key;
  551.                                             FileInfo -> fib_DirEntryType    = -1;
  552.                                             FileInfo -> fib_Protection    = FIBF_EXECUTE|FIBF_DELETE;
  553.                                             FileInfo -> fib_Size        = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces * (DosEnvec -> de_SizeBlock << 2);
  554.                                             FileInfo -> fib_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  555.  
  556.                                             DateStamp(&FileInfo -> fib_Date);
  557.  
  558.                                             memcpy(FileInfo -> fib_FileName,BADDR(FlatNode -> fn_DevInfo -> dn_Name),((UBYTE *)BADDR(FlatNode -> fn_DevInfo -> dn_Name))[0] + 1);
  559.  
  560.                                             DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  561.  
  562.                                             if(!DoIO(DiskRequest))
  563.                                             {
  564.                                                 if(DiskRequest -> iotd_Req . io_Actual)
  565.                                                     FileInfo -> fib_Protection |= FIBF_WRITE;
  566.                                             }
  567.  
  568.                                             DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  569.  
  570.                                             if(!DoIO(DiskRequest))
  571.                                             {
  572.                                                 if(DiskRequest -> iotd_Req . io_Actual)
  573.                                                 {
  574.                                                     FileInfo -> fib_Protection |= FIBF_READ|FIBF_WRITE;
  575.  
  576.                                                     FileInfo -> fib_Size = FileInfo -> fib_NumBlocks = 0;
  577.                                                 }
  578.                                             }
  579.  
  580.                                             Success = TRUE;
  581.  
  582.                                             CloseDevice(DiskRequest);
  583.                                         }
  584.  
  585.                                         DeleteExtIO(DiskRequest);
  586.                                     }
  587.  
  588.                                     DeletePort(DiskPort);
  589.                                 }
  590.                             }
  591.                             else
  592.                             {
  593.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_MORE_ENTRIES,HandlerProc);
  594.                                 break;
  595.                             }
  596.                         }
  597.  
  598.                         if(Success)
  599.                         {
  600.                             FlatPacket -> dp_Res1 = DOSTRUE;
  601.  
  602.                             ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  603.                         }
  604.                         else
  605.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  606.                     }
  607.                     else
  608.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  609.  
  610.                     break;
  611.  
  612.                     /* Open any file for reading/writing. */
  613.  
  614.                 case ACTION_FINDINPUT:
  615.                 case ACTION_FINDOUTPUT:
  616.                 case ACTION_FINDUPDATE:    
  617.  
  618.                         /* Convert the file name. */
  619.  
  620.                     BtoCStr(NameBuffer,FlatPacket -> dp_Arg3,256);
  621.  
  622.                     if(FileName = BaseName(NameBuffer))
  623.                     {
  624.                         LONG Mode;
  625.  
  626.                             /* Only the MODE_OLDFILE type allows
  627.                              * shared data access.
  628.                              */
  629.  
  630.                         if(FlatPacket -> dp_Type == ACTION_FINDINPUT)
  631.                             Mode = SHARED_LOCK;
  632.                         else
  633.                             Mode = EXCLUSIVE_LOCK;
  634.  
  635.                         FileHandle = (struct FileHandle *)BADDR(FlatPacket -> dp_Arg1);
  636.  
  637.                             /* Is there already a lock or filehandle by this
  638.                              * name?
  639.                              */
  640.  
  641.                         if(FlatNode = FindFlatNodeByName(FileName))
  642.                         {
  643.                                 /* If so, is it locked? */
  644.  
  645.                             if((FlatNode -> fn_Mode != Mode) || (Mode == EXCLUSIVE_LOCK && FlatNode -> fn_Mode == EXCLUSIVE_LOCK))
  646.                             {
  647.                                 ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  648.                                 break;
  649.                             }
  650.                         }
  651.  
  652.                             /* Create a new list entry. */
  653.  
  654.                         if(FlatNode = CreateNode(Mode,FileName))
  655.                         {
  656.                             AddTail(&FlatList,(struct Node *)FlatNode);
  657.  
  658.                             FileHandle -> fh_Arg1 = FlatNode -> fn_UniqueID;
  659.  
  660.                                 /* Turn on the disk motor. */
  661.  
  662.                             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = TD_MOTOR;
  663.                             FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = 1;
  664.  
  665.                             DoIO(FlatNode -> fn_DiskRequest);
  666.  
  667.                             ReturnPacket(FlatPacket,DOSTRUE,FlatPacket -> dp_Res2,HandlerProc);
  668.                         }
  669.                         else
  670.                             ReturnPacket(FlatPacket,DOSFALSE,ERROR_NO_FREE_STORE,HandlerProc);
  671.                     }
  672.                     else
  673.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_NOT_FOUND,HandlerProc);
  674.  
  675.                     break;
  676.  
  677.                     /* Close a file opened above. */
  678.  
  679.                 case ACTION_END:
  680.  
  681.                         /* Find the node. */
  682.  
  683.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  684.                     {
  685.                             /* Turn off the motor. */
  686.  
  687.                         FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = TD_MOTOR;
  688.                         FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = 0;
  689.  
  690.                         DoIO(FlatNode -> fn_DiskRequest);
  691.  
  692.                         Remove((struct Node *)FlatNode);
  693.  
  694.                         DeleteNode(FlatNode);
  695.                     }
  696.  
  697.                     ReturnPacket(FlatPacket,DOSTRUE,0,HandlerProc);
  698.                     break;
  699.  
  700.                     /* Read a couple of bytes from a file. */
  701.  
  702.                 case ACTION_READ:
  703.  
  704.                         /* Do we have a valid filehandle? */
  705.  
  706.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  707.                     {
  708.                         ReadBytes = FlatPacket -> dp_Arg3;
  709.  
  710.                             /* Reading across the data media size? */
  711.  
  712.                         if(FlatNode -> fn_Position + ReadBytes > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
  713.                             ReadBytes = -1;
  714.  
  715.                         FlatPacket -> dp_Res2 = 0;
  716.  
  717.                             /* Read a few bytes. */
  718.  
  719.                         if(ReadBytes > 0)
  720.                         {
  721.                             if(Bytes = DoRead(FlatNode,ReadBytes,(APTR)FlatPacket -> dp_Arg2,FlatPacket -> dp_Port -> mp_SigTask))
  722.                                 FlatNode -> fn_Position += Bytes;
  723.  
  724.                             FlatPacket -> dp_Res1 = Bytes;
  725.                         }
  726.                         else
  727.                         {
  728.                             if(ReadBytes == 0)
  729.                                 FlatPacket -> dp_Res1 = 0;
  730.                             else
  731.                                 FlatPacket -> dp_Res1 = -1;
  732.                         }
  733.  
  734.                         ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  735.                     }
  736.                     else
  737.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
  738.  
  739.                     break;
  740.  
  741.                     /* Write a few bytes to a file. */
  742.  
  743.                 case ACTION_WRITE:
  744.  
  745.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  746.                     {
  747.                         WriteBytes = FlatPacket -> dp_Arg3;
  748.  
  749.                         if(FlatNode -> fn_Position + WriteBytes > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
  750.                             WriteBytes = -1;
  751.  
  752.                         FlatPacket -> dp_Res2 = 0;
  753.  
  754.                         if(WriteBytes > 0)
  755.                         {
  756.                             if(Bytes = DoWrite(FlatNode,WriteBytes,(APTR)FlatPacket -> dp_Arg2,FlatPacket -> dp_Port -> mp_SigTask))
  757.                                 FlatNode -> fn_Position += Bytes;
  758.  
  759.                             FlatPacket -> dp_Res1 = Bytes;
  760.                         }
  761.                         else
  762.                         {
  763.                             if(WriteBytes == 0)
  764.                                 FlatPacket -> dp_Res1 = 0;
  765.                             else
  766.                                 FlatPacket -> dp_Res1 = -1;
  767.                         }
  768.  
  769.                         ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  770.                     }
  771.                     else
  772.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
  773.  
  774.                     break;
  775.  
  776.                     /* Move the r/w pointer inside a file. */
  777.  
  778.                 case ACTION_SEEK:
  779.  
  780.                     if(FlatNode = FindFlatNodeByID(FlatPacket -> dp_Arg1))
  781.                     {
  782.                         if(FlatPacket -> dp_Arg3 == OFFSET_BEGINNING)
  783.                             NewPosition = FlatPacket -> dp_Arg2;
  784.  
  785.                         if(FlatPacket -> dp_Arg3 == OFFSET_CURRENT)
  786.                             NewPosition = FlatNode -> fn_Position + FlatPacket -> dp_Arg2;
  787.  
  788.                         if(FlatPacket -> dp_Arg3 == OFFSET_END)
  789.                             NewPosition = FlatNode -> fn_Position - FlatPacket -> dp_Arg2;
  790.  
  791.                         if(NewPosition < 0 || NewPosition > (FlatNode -> fn_BlockSize * FlatNode -> fn_NumBlocks))
  792.                         {
  793.                             FlatPacket -> dp_Res1 = -1;
  794.                             FlatPacket -> dp_Res2 = ERROR_SEEK_ERROR;
  795.                         }
  796.                         else
  797.                         {
  798.                             FlatPacket -> dp_Res1 = FlatNode -> fn_Position;
  799.  
  800.                             FlatNode -> fn_Position = NewPosition;
  801.                         }
  802.  
  803.                         ReturnPacket(FlatPacket,FlatPacket -> dp_Res1,FlatPacket -> dp_Res2,HandlerProc);
  804.                     }
  805.                     else
  806.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_WRONG_TYPE,HandlerProc);
  807.  
  808.                     break;
  809.  
  810.                     /* Remove the handler. */
  811.  
  812.                 case ACTION_DIE:
  813.  
  814.                         /* Are we allowed to remove ourselves? */
  815.  
  816.                     if(!FlatList . lh_Head -> ln_Succ)
  817.                     {
  818.                         ReturnPacket(FlatPacket,DOSTRUE,0,HandlerProc);
  819.  
  820.                         goto FallOff;
  821.                     }
  822.                     else
  823.                         ReturnPacket(FlatPacket,DOSFALSE,ERROR_OBJECT_IN_USE,HandlerProc);
  824.  
  825.                     break;
  826.  
  827.                     /* Ignore the rest of the packets. */
  828.  
  829.                 default:
  830.  
  831.                     ReturnPacket(FlatPacket,DOSFALSE,ERROR_ACTION_NOT_KNOWN,HandlerProc);
  832.                     break;
  833.             }
  834.         }
  835.  
  836.             /* Cease actions, close libraries and exit. */
  837.  
  838. FallOff:    FlatDevNode -> dn_Task = NULL;
  839.  
  840.         if(IntuitionBase)
  841.             CloseLibrary(IntuitionBase);
  842.  
  843.         if(DOSBase)
  844.             CloseLibrary(DOSBase);
  845.     }
  846. }
  847.  
  848.     /* BaseName(UBYTE *String):
  849.      *
  850.      *    Returns the base of a filename.
  851.      */
  852.  
  853. UBYTE * __regargs
  854. BaseName(UBYTE *String)
  855. {
  856.     if(String[0])
  857.     {
  858.         SHORT i;
  859.  
  860.         for(i = strlen(String) - 1 ; i >= 0 ; i--)
  861.         {
  862.             if(String[i] == ':' || String[i] == '/')
  863.             {
  864.                 if(String[i + 1])
  865.                     return(&String[i + 1]);
  866.                 else
  867.                     return(NULL);
  868.             }
  869.         }
  870.  
  871.         return(String);
  872.     }
  873.     else
  874.         return(NULL);
  875. }
  876.  
  877.     /* Local2Upper(UBYTE c):
  878.      *
  879.      *    Convert a character to upper case.
  880.      */
  881.  
  882. UBYTE __regargs
  883. Local2Upper(UBYTE c)
  884. {
  885.     return((UBYTE)((((c) >= 224 && (c) <= 254) || ((c) >= 'a' && (c) <= 'z')) ? (c) - 32 : c));
  886. }
  887.  
  888.     /* StrCmp(UBYTE *a,UBYTE *b):
  889.      *
  890.      *    Do string comparison ignoring case.
  891.      */
  892.  
  893. UBYTE __regargs
  894. StrCmp(UBYTE *a,UBYTE *b)
  895. {
  896.     for( ; Local2Upper(*a) == Local2Upper(*b) ; a++, b++)
  897.     {
  898.         if(!(*a))
  899.             return(0);
  900.     }
  901.  
  902.     return((UBYTE)(Local2Upper(*a) - Local2Upper(*b)));
  903. }
  904.  
  905.     /* FindFlatNodeByID(ULONG UniqueID):
  906.      *
  907.      *    Scan the item list looking for a list entry with
  908.      *    a matching ID.
  909.      */
  910.  
  911. struct FlatNode * __regargs
  912. FindFlatNodeByID(ULONG UniqueID)
  913. {
  914.     struct FlatNode *Node;
  915.  
  916.     Node = (struct FlatNode *)FlatList . lh_Head;
  917.  
  918.     while(Node -> fn_Succ)
  919.     {
  920.         if(Node -> fn_UniqueID == UniqueID)
  921.             return(Node);
  922.  
  923.         Node = Node -> fn_Succ;
  924.     }
  925.  
  926.     return(NULL);
  927. }
  928.  
  929.     /* FindFlatNodeByName(UBYTE *Name):
  930.      *
  931.      *    Scan the item list looking for an entry with a
  932.      *    matching name.
  933.      */
  934.  
  935. struct FlatNode * __regargs
  936. FindFlatNodeByName(UBYTE *Name)
  937. {
  938.     struct FlatNode *Node;
  939.  
  940.     Node = (struct FlatNode *)FlatList . lh_Head;
  941.  
  942.     while(Node -> fn_Succ)
  943.     {
  944.         if(!StrCmp(Node -> fn_Name,Name))
  945.             return(Node);
  946.  
  947.         Node = Node -> fn_Succ;
  948.     }
  949.  
  950.     return(NULL);
  951. }
  952.  
  953.     /* BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength):
  954.      *
  955.      *    Convert a BCPL string into a `C' string.
  956.      */
  957.  
  958. VOID __regargs
  959. BtoCStr(UBYTE *Name,BSTR String,LONG MaxLength)
  960. {
  961.     UBYTE *Src,Length;
  962.  
  963.     if(Src = (UBYTE *)BADDR(String))
  964.     {
  965.         if((Length = Src[0]) > MaxLength)
  966.             Length = MaxLength;
  967.  
  968.         Src++;
  969.  
  970.         while(Length--)
  971.             *Name++ = *Src++;
  972.  
  973.         *Name = 0;
  974.     }
  975. }
  976.  
  977.     /* ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive):
  978.      *
  979.      *    If trouble shows up, behave like the standard
  980.      *    FS and complain.
  981.      */
  982.  
  983. LONG __regargs
  984. ShowRequest(APTR WindowPtr,BYTE Type,UBYTE *Drive)
  985. {
  986.     STATIC struct IntuiText DiskWriteProtected[3] =
  987.     {
  988.         {0,1,JAM2,15, 5,NULL,"Disk in drive",                    &DiskWriteProtected[1]},
  989.         {0,1,JAM2,15,15,NULL,"################################",    &DiskWriteProtected[2]},
  990.         {0,1,JAM2,15,25,NULL,"is write protected",            NULL}
  991.     };
  992.  
  993.     STATIC struct IntuiText DiskNotPresent[2] =
  994.     {
  995.         {0,1,JAM2,15, 5,NULL,"No disk present in drive",        &DiskNotPresent[1]},
  996.         {0,1,JAM2,15,15,NULL,"################################",    NULL}
  997.     };
  998.  
  999.     STATIC struct IntuiText DiskUnreadable[3] =
  1000.     {
  1001.         {0,1,JAM2,15, 5,NULL,"Disk in drive",                &DiskUnreadable[1]},
  1002.         {0,1,JAM2,15,15,NULL,"################################",    &DiskUnreadable[2]},
  1003.         {0,1,JAM2,15,25,NULL,"is unreadable",                NULL}
  1004.     };
  1005.  
  1006.     STATIC struct IntuiText DiskWriteError[2] =
  1007.     {
  1008.         {0,1,JAM2,15, 5,NULL,"Error writing to drive",            &DiskWriteError[1]},
  1009.         {0,1,JAM2,15,15,NULL,"################################",    NULL}
  1010.     };
  1011.  
  1012.     STATIC struct IntuiText Retry =
  1013.     {
  1014.         0,1,JAM2,7,3,NULL,"Retry",NULL
  1015.     };
  1016.  
  1017.     STATIC struct IntuiText Cancel =
  1018.     {
  1019.         0,1,JAM2,7,3,NULL,"Cancel",NULL
  1020.     };
  1021.  
  1022.         /* A -1 will result in cancelling the
  1023.          * requester.
  1024.          */
  1025.  
  1026.     if(WindowPtr != (APTR)-1)
  1027.     {
  1028.         struct IntuiText    *BodyText;
  1029.         SHORT             i;
  1030.  
  1031.             /* Install the right alert type. */
  1032.  
  1033.         switch(Type)
  1034.         {
  1035.             case ERR_WRITEPROTECT:    BodyText = DiskWriteProtected;
  1036.                         break;
  1037.  
  1038.             case ERR_NODISK:    BodyText = DiskNotPresent;
  1039.                         break;
  1040.  
  1041.             case ERR_UNREADABLE:    BodyText = DiskUnreadable;
  1042.                         break;
  1043.  
  1044.             case ERR_WRITEERROR:    BodyText = DiskWriteError;
  1045.                         break;
  1046.         }
  1047.  
  1048.             /* Add the drive name. */
  1049.  
  1050.         for(i = 0 ; BodyText[1] . IText[i] = Local2Upper(Drive[i + 1]) ; i++);
  1051.  
  1052.             /* Show the requester. */
  1053.  
  1054.         return((LONG)AutoRequest(WindowPtr,BodyText,&Retry,&Cancel,DISKINSERTED,NULL,320,72));
  1055.     }
  1056.  
  1057.     return(FALSE);
  1058. }
  1059.  
  1060.     /* FindDevice():
  1061.      *
  1062.      *    Find a DeviceNode entry in the DosList.
  1063.      */
  1064.  
  1065. struct DeviceNode * __regargs
  1066. FindDevice(struct DeviceNode *LastNode,struct FileSysStartupMsg    **Startup,struct DosEnvec **DosEnvec,UBYTE *Name)
  1067. {
  1068.     struct DeviceNode    *DevInfo;
  1069.     STATIC UBYTE         NameBuffer[257];
  1070.  
  1071.     Forbid();
  1072.  
  1073.     if(LastNode)
  1074.         DevInfo = (struct DeviceNode *)BADDR(LastNode -> dn_Next);
  1075.     else
  1076.         DevInfo = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info)) -> di_DevInfo);
  1077.  
  1078.     while(DevInfo)
  1079.     {
  1080.         if(DevInfo -> dn_Type == DLT_DEVICE && DevInfo -> dn_Task && DevInfo -> dn_Startup)
  1081.         {
  1082.             if(Name)
  1083.             {
  1084.                 BtoCStr(NameBuffer,DevInfo -> dn_Name,256);
  1085.  
  1086.                 if(!StrCmp(NameBuffer,Name))
  1087.                 {
  1088.                     if(Startup)
  1089.                         *Startup = (struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup);
  1090.  
  1091.                     if(DosEnvec)
  1092.                         *DosEnvec = (struct DosEnvec *)BADDR(((struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup)) -> fssm_Environ);
  1093.  
  1094.                     Permit();
  1095.  
  1096.                     return(DevInfo);
  1097.                 }
  1098.             }
  1099.             else
  1100.             {
  1101.                 if(Startup)
  1102.                     *Startup = (struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup);
  1103.  
  1104.                 if(DosEnvec)
  1105.                     *DosEnvec = (struct DosEnvec *)BADDR(((struct FileSysStartupMsg *)BADDR(DevInfo -> dn_Startup)) -> fssm_Environ);
  1106.  
  1107.                 Permit();
  1108.  
  1109.                 return(DevInfo);
  1110.             }
  1111.         }
  1112.  
  1113.         DevInfo = (struct DeviceNode *)BADDR(DevInfo -> dn_Next);
  1114.     }
  1115.  
  1116.     Permit();
  1117.  
  1118.     return(NULL);
  1119. }
  1120.  
  1121.     /* DeleteNode(struct FlatNode *FlatNode):
  1122.      *
  1123.      *    Delete a freshly created item node freeing
  1124.      *    all associated resources.
  1125.      */
  1126.  
  1127. VOID __regargs
  1128. DeleteNode(struct FlatNode *FlatNode)
  1129. {
  1130.     if(FlatNode -> fn_DiskBuffer)
  1131.         FreeMem(FlatNode -> fn_DiskBuffer,FlatNode -> fn_BlockSize);
  1132.  
  1133.     if(FlatNode -> fn_DiskRequest)
  1134.     {
  1135.         if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Device)
  1136.             CloseDevice(FlatNode -> fn_DiskRequest);
  1137.  
  1138.         DeleteExtIO(FlatNode -> fn_DiskRequest);
  1139.     }
  1140.  
  1141.     if(FlatNode -> fn_DiskPort)
  1142.         DeletePort(FlatNode -> fn_DiskPort);
  1143.  
  1144.     FreeMem(FlatNode,sizeof(struct FlatNode));
  1145. }
  1146.  
  1147.     /* CreateNode(LONG Type,UBYTE *Name):
  1148.      *
  1149.      *    Create an item node with given characteristics,
  1150.      *    can be either shared or exclusive access, if a name
  1151.      *    is given will open the approriate device driver.     
  1152.      */
  1153.  
  1154. struct FlatNode * __regargs
  1155. CreateNode(LONG Type,UBYTE *Name)
  1156. {
  1157.     struct FlatNode *FlatNode;
  1158.  
  1159.     if(FlatNode = (struct FlatNode *)AllocMem(sizeof(struct FlatNode),MEMF_PUBLIC|MEMF_CLEAR))
  1160.     {
  1161.         if(Name)
  1162.         {
  1163.             struct DeviceNode        *DevInfo;
  1164.             struct FileSysStartupMsg    *Startup;
  1165.             struct DosEnvec            *DosEnvec;
  1166.  
  1167.                 /* Try to find the device. */
  1168.  
  1169.             if(!(DevInfo = FindDevice(NULL,&Startup,&DosEnvec,Name)))
  1170.             {
  1171.                 DeleteNode(FlatNode);
  1172.  
  1173.                 return(NULL);
  1174.             }
  1175.  
  1176.                 /* Create a MsgPort, this is where a
  1177.                  * potential problem exists: since all
  1178.                  * MsgPorts refer to the handler process,
  1179.                  * we will run out of signal bits if
  1180.                  * more than app. 16 files/locks are open at
  1181.                  * the same time.
  1182.                  */
  1183.  
  1184.             if(!(FlatNode -> fn_DiskPort = (struct MsgPort *)CreatePort(NULL,0)))
  1185.             {
  1186.                 DeleteNode(FlatNode);
  1187.  
  1188.                 return(NULL);
  1189.             }
  1190.  
  1191.                 /* Create a device request. */
  1192.  
  1193.             if(!(FlatNode -> fn_DiskRequest = (struct IOExtTD *)CreateExtIO(FlatNode -> fn_DiskPort,sizeof(struct IOExtTD))))
  1194.             {
  1195.                 DeleteNode(FlatNode);
  1196.  
  1197.                 return(NULL);
  1198.             }
  1199.  
  1200.                 /* Open the device driver. */
  1201.  
  1202.             if(OpenDevice(&((UBYTE *)BADDR(Startup -> fssm_Device))[1],Startup -> fssm_Unit,FlatNode -> fn_DiskRequest,Startup -> fssm_Flags))
  1203.             {
  1204.                 DeleteNode(FlatNode);
  1205.  
  1206.                 return(NULL);
  1207.             }
  1208.  
  1209.                 /* Inquire the unit data. */
  1210.  
  1211.             FlatNode -> fn_BlockSize    = DosEnvec -> de_SizeBlock << 2;
  1212.             FlatNode -> fn_FirstBlock    = DosEnvec -> de_LowCyl * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  1213.             FlatNode -> fn_NumBlocks    = (DosEnvec -> de_HighCyl - DosEnvec -> de_LowCyl + 1) * DosEnvec -> de_BlocksPerTrack * DosEnvec -> de_Surfaces;
  1214.  
  1215.                 /* Create a r/w buffer. */
  1216.  
  1217.             if(!(FlatNode -> fn_DiskBuffer = (APTR)AllocMem(FlatNode -> fn_BlockSize,DosEnvec -> de_BufMemType)))
  1218.             {
  1219.                 DeleteNode(FlatNode);
  1220.  
  1221.                 return(NULL);
  1222.             }
  1223.  
  1224.             strcpy(&FlatNode -> fn_Name[1],Name);
  1225.         }
  1226.  
  1227.         FlatNode -> fn_Mode    = Type;
  1228.         FlatNode -> fn_UniqueID    = UniqueCounter++;
  1229.     }
  1230.  
  1231.     return(FlatNode);
  1232. }
  1233.  
  1234.     /* ReturnPacket():
  1235.      *
  1236.      *    Return a standard DOS packet to its sender.
  1237.      */
  1238.  
  1239. VOID __regargs
  1240. ReturnPacket(struct DosPacket *Packet,ULONG Res1,ULONG Res2,struct Process *HandlerProc)
  1241. {
  1242.     struct MsgPort *ReplyPort;
  1243.  
  1244.     ReplyPort = Packet -> dp_Port;
  1245.  
  1246.     Packet -> dp_Res1 = Res1;
  1247.     Packet -> dp_Res2 = Res2;
  1248.  
  1249.     Packet -> dp_Port = &HandlerProc -> pr_MsgPort;
  1250.  
  1251.     Packet -> dp_Link -> mn_Node . ln_Name    = (APTR)Packet;
  1252.     Packet -> dp_Link -> mn_Node . ln_Succ    = NULL;
  1253.     Packet -> dp_Link -> mn_Node . ln_Pred    = NULL;
  1254.  
  1255.     PutMsg(ReplyPort,Packet -> dp_Link);
  1256. }
  1257.  
  1258.     /* WaitPacket(struct Process *HandlerProc):
  1259.      *
  1260.      *    Wait for packet arrival.
  1261.      */
  1262.  
  1263. struct DosPacket * __regargs
  1264. WaitPacket(struct Process *HandlerProc)
  1265. {
  1266.     struct Message *DOSMsg;
  1267.  
  1268.     WaitPort(&HandlerProc -> pr_MsgPort);
  1269.  
  1270.     DOSMsg = (struct Message *)GetMsg(&HandlerProc -> pr_MsgPort);
  1271.  
  1272.     return((struct DosPacket *)DOSMsg -> mn_Node . ln_Name);
  1273. }
  1274.  
  1275.     /* DoRead():
  1276.      *
  1277.      *    Read a few bytes from a file.
  1278.      */
  1279.  
  1280. LONG __regargs
  1281. DoRead(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller)
  1282. {
  1283.     LONG Block,Length,BytesRead = 0,Offset = FlatNode -> fn_Position;
  1284.     UBYTE *DiskBuffer = FlatNode -> fn_DiskBuffer;
  1285.  
  1286.         /* Time for a check? */
  1287.  
  1288.     if(!FlatNode -> fn_CheckCount)
  1289.     {
  1290.         FOREVER
  1291.         {
  1292.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1293.  
  1294.                 /* Is there still a disk in the drive? */
  1295.  
  1296.             if(!DoIO(FlatNode -> fn_DiskRequest))
  1297.             {
  1298.                 if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
  1299.                 {
  1300.                     if(!ShowRequest(Caller -> pr_WindowPtr,ERR_NODISK,FlatNode -> fn_Name))
  1301.                         return(0);
  1302.                 }
  1303.                 else
  1304.                     break;
  1305.             }
  1306.         }
  1307.     }
  1308.  
  1309.     if(FlatNode -> fn_CheckCount++ == 10)
  1310.         FlatNode -> fn_CheckCount = 0;
  1311.  
  1312.         /* Convert offset from bytes into blocks. */
  1313.  
  1314.     Block    = Offset / FlatNode -> fn_BlockSize;
  1315.     Offset    = Offset % FlatNode -> fn_BlockSize;
  1316.  
  1317.     if(Size > 0)
  1318.     {
  1319.             /* Read the data block by block... */
  1320.  
  1321.         while(Size > 0)
  1322.         {
  1323. Retry:            FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_READ;
  1324.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
  1325.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1326.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1327.  
  1328.                 /* Read the block. */
  1329.  
  1330.             if(DoIO(FlatNode -> fn_DiskRequest))
  1331.             {
  1332.                 if(ShowRequest(Caller -> pr_WindowPtr,ERR_UNREADABLE,FlatNode -> fn_Name))
  1333.                     goto Retry;
  1334.                 else
  1335.                     return(BytesRead);
  1336.             }
  1337.  
  1338.             Length = FlatNode -> fn_BlockSize - Offset;
  1339.  
  1340.             if(Length > Size)
  1341.                 Length = Size;
  1342.  
  1343.                 /* Copy the data. */
  1344.  
  1345.             memcpy(Buffer,&DiskBuffer[Offset],Length);
  1346.  
  1347.             Buffer = &Buffer[Length];
  1348.  
  1349.             Size -= Length;
  1350.  
  1351.             BytesRead += Length;
  1352.  
  1353.             Block++;
  1354.  
  1355.             Offset = 0;
  1356.         }
  1357.     }
  1358.  
  1359.     return(BytesRead);
  1360. }
  1361.  
  1362.     /* DoWrite():
  1363.      *
  1364.      *    Write a few bytes to a file. 
  1365.      */
  1366.  
  1367. LONG __regargs
  1368. DoWrite(struct FlatNode *FlatNode,LONG Size,UBYTE *Buffer,struct Process *Caller)
  1369. {
  1370.     LONG Block,Length,BytesWritten = 0,Offset = FlatNode -> fn_Position;
  1371.     UBYTE *DiskBuffer = FlatNode -> fn_DiskBuffer;
  1372.  
  1373.         /* Time for a check? */
  1374.  
  1375.     if(!FlatNode -> fn_CheckCount)
  1376.     {
  1377.         FOREVER
  1378.         {
  1379.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_CHANGESTATE;
  1380.  
  1381.                 /* Is there a disk in the drive? */
  1382.  
  1383.             if(!DoIO(FlatNode -> fn_DiskRequest))
  1384.             {
  1385.                 if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
  1386.                 {
  1387.                     if(!ShowRequest(Caller -> pr_WindowPtr,ERR_NODISK,FlatNode -> fn_Name))
  1388.                         return(0);
  1389.                 }
  1390.                 else
  1391.                     break;
  1392.             }
  1393.         }
  1394.  
  1395.         FOREVER
  1396.         {
  1397.             FlatNode -> fn_DiskRequest -> iotd_Req . io_Command = TD_PROTSTATUS;
  1398.  
  1399.                 /* Is the disk write enabled? */
  1400.  
  1401.             if(!DoIO(FlatNode -> fn_DiskRequest))
  1402.             {
  1403.                 if(FlatNode -> fn_DiskRequest -> iotd_Req . io_Actual)
  1404.                 {
  1405.                     if(!ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEPROTECT,FlatNode -> fn_Name))
  1406.                         return(0);
  1407.                 }
  1408.                 else
  1409.                     break;
  1410.             }
  1411.         }
  1412.     }
  1413.  
  1414.     if(FlatNode -> fn_CheckCount++ == 10)
  1415.         FlatNode -> fn_CheckCount = 0;
  1416.  
  1417.         /* Convert offset from bytes into blocks. */
  1418.  
  1419.     Block    = Offset / FlatNode -> fn_BlockSize;
  1420.     Offset    = Offset % FlatNode -> fn_BlockSize;
  1421.  
  1422.     if(Size > 0)
  1423.     {
  1424.         while(Size > 0)
  1425.         {
  1426. Retry1:            if(Offset)
  1427.             {
  1428.                     /* The data to write is smaller
  1429.                      * than a block, so we'll have to
  1430.                      * read the block to write to first,
  1431.                      * copy the data over and write the
  1432.                      * block back.
  1433.                      */
  1434.  
  1435.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_READ;
  1436.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
  1437.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1438.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1439.  
  1440.                 if(DoIO(FlatNode -> fn_DiskRequest))
  1441.                 {
  1442.                     if(ShowRequest(Caller -> pr_WindowPtr,ERR_UNREADABLE,FlatNode -> fn_Name))
  1443.                         goto Retry1;
  1444.                     else
  1445.                         return(BytesWritten);
  1446.                 }
  1447.  
  1448.                 Length = FlatNode -> fn_BlockSize - Offset;
  1449.  
  1450.                 if(Length > Size)
  1451.                     Length = Size;
  1452.  
  1453.                 memcpy(&DiskBuffer[Offset],Buffer,Length);
  1454.  
  1455. Retry2:                FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_WRITE;
  1456.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
  1457.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1458.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1459.  
  1460.                 if(DoIO(FlatNode -> fn_DiskRequest))
  1461.                 {
  1462.                     if(ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEERROR,FlatNode -> fn_Name))
  1463.                         goto Retry2;
  1464.                     else
  1465.                         return(BytesWritten);
  1466.                 }
  1467.  
  1468.                 Buffer = &Buffer[Length];
  1469.  
  1470.                 Size -= Length;
  1471.  
  1472.                 BytesWritten += Length;
  1473.  
  1474.                 Block++;
  1475.  
  1476.                 Offset = 0;
  1477.             }
  1478.             else
  1479.             {
  1480.                 if(Size > FlatNode -> fn_BlockSize)
  1481.                     Length = FlatNode -> fn_BlockSize;
  1482.                 else
  1483.                 {
  1484.                     if(Size < FlatNode -> fn_BlockSize)
  1485.                         memset(DiskBuffer,0,FlatNode -> fn_BlockSize);
  1486.  
  1487.                     Length = Size;
  1488.                 }
  1489.  
  1490.                 memcpy(DiskBuffer,Buffer,Length);
  1491.  
  1492. Retry3:                FlatNode -> fn_DiskRequest -> iotd_Req . io_Command    = CMD_WRITE;
  1493.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Offset    = Block * FlatNode -> fn_BlockSize + FlatNode -> fn_FirstBlock;
  1494.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Length    = FlatNode -> fn_BlockSize;
  1495.                 FlatNode -> fn_DiskRequest -> iotd_Req . io_Data    = DiskBuffer;
  1496.  
  1497.                 if(DoIO(FlatNode -> fn_DiskRequest))
  1498.                 {
  1499.                     if(ShowRequest(Caller -> pr_WindowPtr,ERR_WRITEERROR,FlatNode -> fn_Name))
  1500.                         goto Retry1;
  1501.                     else
  1502.                         return(BytesWritten);
  1503.                 }
  1504.  
  1505.                 Buffer = &Buffer[Length];
  1506.  
  1507.                 Size -= Length;
  1508.  
  1509.                 BytesWritten += Length;
  1510.  
  1511.                 Block++;
  1512.             }
  1513.         }
  1514.     }
  1515.  
  1516.     return(BytesWritten);
  1517. }
  1518.