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