home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / ma93 / FastIO_II / asyncio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-19  |  21.2 KB  |  668 lines

  1. ;/* ASyncIO.c - Execute me to compile with SAS/C 5.10b
  2. sc data=near nominc strmer streq nostkchk saveds ign=73 AsyncIO.c
  3. ;lc -cfist -v -j73 asyncio.c
  4. quit
  5. */
  6.  
  7. /* (c)  Copyright 1993 Commodore-Amiga, Inc.   All rights reserved. */
  8. /* The information contained herein is subject to change without    */
  9. /* notice, and is provided "as is" without warranty of any kind,    */
  10. /* either expressed or implied.  The entire risk as to the use of   */
  11. /* this information is assumed by the user.                         */
  12.  
  13. #include <exec/types.h>
  14. #include <exec/memory.h>
  15. #include <dos/dos.h>
  16. #include <dos/dosextens.h>
  17.  
  18. #include <clib/exec_protos.h>
  19. #include <clib/dos_protos.h>
  20.  
  21. #include <pragmas/exec_pragmas.h>
  22. #include <pragmas/dos_pragmas.h>
  23.  
  24. #include "asyncio.h"
  25.  
  26.  
  27. /*****************************************************************************/
  28.  
  29.  
  30. extern struct Library *DOSBase;
  31. extern struct Library *SysBase;
  32.  
  33.  
  34. /*****************************************************************************/
  35.  
  36.  
  37. /* this macro lets us long-align structures on the stack */
  38. #define D_S(type,name) char a_##name[sizeof(type)+3]; \
  39.                        type *name = (type *)((LONG)(a_##name+3) & ~3);
  40.  
  41.  
  42. /*****************************************************************************/
  43.  
  44.  
  45. /* send out an async packet to the file system. */
  46. static VOID SendPacket(struct AsyncFile *file, APTR arg2)
  47. {
  48.     file->af_Packet.sp_Pkt.dp_Port = &file->af_PacketPort;
  49.     file->af_Packet.sp_Pkt.dp_Arg2 = (LONG)arg2;
  50.     PutMsg(file->af_Handler, &file->af_Packet.sp_Msg);
  51.     file->af_PacketPending = TRUE;
  52. }
  53.  
  54.  
  55. /*****************************************************************************/
  56.  
  57.  
  58. /* this function waits for a packet to come back from the file system. If no
  59.  * packet is pending, state from the previous packet is returned. This ensures
  60.  * that once an error occurs, it state is maintained for the rest of the life
  61.  * of the file handle.
  62.  *
  63.  * This function also deals with IO errors, bringing up the needed DOS
  64.  * requesters to let the user retry an operation or cancel it.
  65.  */
  66. static LONG WaitPacket(struct AsyncFile *file)
  67. {
  68. LONG bytes;
  69.  
  70.     if (file->af_PacketPending)
  71.     {
  72.         /* mark packet as no longer pending since we are going to get it */
  73.         file->af_PacketPending = FALSE;
  74.  
  75.         while (TRUE)
  76.         {
  77.             /* This enables signalling when a packet comes back to the port */
  78.             file->af_PacketPort.mp_Flags = PA_SIGNAL;
  79.  
  80.             /* Wait for the packet to come back, and remove it from the message
  81.              * list. Since we know no other packets can come in to the port, we can
  82.              * safely use Remove() instead of GetMsg(). If other packets could come in,
  83.              * we would have to use GetMsg(), which correctly arbitrates access in such
  84.              * a case
  85.              */
  86.             Remove((struct Node *)WaitPort(&file->af_PacketPort));
  87.  
  88.             /* set the port type back to PA_IGNORE so we won't be bothered with
  89.              * spurious signals
  90.              */
  91.             file->af_PacketPort.mp_Flags = PA_IGNORE;
  92.  
  93.             bytes = file->af_Packet.sp_Pkt.dp_Res1;
  94.             if (bytes >= 0)
  95.             {
  96.                 /* packet didn't report an error, so bye... */
  97.                 return(bytes);
  98.             }
  99.  
  100.             /* see if the user wants to try again... */
  101.             if (ErrorReport(file->af_Packet.sp_Pkt.dp_Res2,
  102.                             REPORT_STREAM,
  103.                             file->af_File,NULL))
  104.                 return(-1);
  105.  
  106.             /* user wants to try again, resend the packet */
  107.             SendPacket(file,file->af_Buffers[file->af_CurrentBuf]);
  108.         }
  109.     }
  110.  
  111.     /* last packet's error code, or 0 if packet was never sent */
  112.     SetIoErr(file->af_Packet.sp_Pkt.dp_Res2);
  113.  
  114.     return(file->af_Packet.sp_Pkt.dp_Res1);
  115. }
  116.  
  117.  
  118. /*****************************************************************************/
  119.  
  120.  
  121. /* this function puts the packet back on the message list of our
  122.  * message port.
  123.  */
  124. static VOID RequeuePacket(struct AsyncFile *file)
  125. {
  126.     AddHead(&file->af_PacketPort.mp_MsgList,&file->af_Packet.sp_Msg.mn_Node);
  127.     file->af_PacketPending = TRUE;
  128. }
  129.  
  130.  
  131. /*****************************************************************************/
  132.  
  133.  
  134. /* this function records a failure from a synchronous DOS call into the
  135.  * packet so that it gets picked up by the other IO routines in this module
  136.  */
  137. VOID RecordSyncFailure(struct AsyncFile *file)
  138. {
  139.     file->af_Packet.sp_Pkt.dp_Res1 = -1;
  140.     file->af_Packet.sp_Pkt.dp_Res2 = IoErr();
  141. }
  142.  
  143.  
  144. /*****************************************************************************/
  145.  
  146.  
  147. struct AsyncFile *OpenAsync(const STRPTR fileName, UBYTE accessMode, LONG bufferSize)
  148. {
  149. struct AsyncFile  *file;
  150. struct FileHandle *fh;
  151. BPTR               handle;
  152. BPTR               lock;
  153. LONG               blockSize;
  154. D_S(struct InfoData,infoData);
  155.  
  156.     handle = NULL;
  157.     file   = NULL;
  158.     lock   = NULL;
  159.  
  160.     if (accessMode == MODE_READ)
  161.     {
  162.         if (handle = Open(fileName,MODE_OLDFILE))
  163.             lock = DupLockFromFH(handle);
  164.     }
  165.     else
  166.     {
  167.         if (accessMode == MODE_WRITE)
  168.         {
  169.             handle = Open(fileName,MODE_NEWFILE);
  170.         }
  171.         else if (accessMode == MODE_APPEND)
  172.         {
  173.             /* in append mode, we open for writing, and then seek to the
  174.              * end of the file. That way, the initial write will happen at
  175.              * the end of the file, thus extending it
  176.              */
  177.  
  178.             if (handle = Open(fileName,MODE_READWRITE))
  179.             {
  180.                 if (Seek(handle,0,OFFSET_END) < 0)
  181.                 {
  182.                     Close(handle);
  183.                     handle = NULL;
  184.                 }
  185.             }
  186.         }
  187.  
  188.         /* we want a lock on the same device as where the file is. We can't
  189.          * use DupLockFromFH() for a write-mode file though. So we get sneaky
  190.          * and get a lock on the parent of the file
  191.          */
  192.         if (handle)
  193.             lock = ParentOfFH(handle);
  194.     }
  195.  
  196.     if (handle)
  197.     {
  198.         /* if it was possible to obtain a lock on the same device as the
  199.          * file we're working on, get the block size of that device and
  200.          * round up our buffer size to be a multiple of the block size.
  201.          * This maximizes DMA efficiency.
  202.          */
  203.  
  204.         blockSize = 512;
  205.         if (lock)
  206.         {
  207.             if (Info(lock,infoData))
  208.             {
  209.                 blockSize = infoData->id_BytesPerBlock;
  210.                 bufferSize =
  211.                     (((bufferSize + blockSize - 1) / blockSize) * blockSize) * 2;
  212.             }
  213.             UnLock(lock);
  214.         }
  215.  
  216.         /* now allocate the ASyncFile structure, as well as the read buffers.
  217.          * Add 15 bytes to the total size in order to allow for later
  218.          * quad-longword alignement of the buffers
  219.          */
  220.  
  221.         if (file = AllocVec(sizeof(struct AsyncFile) + bufferSize + 15,MEMF_ANY))
  222.         {
  223.             file->af_File      = handle;
  224.             file->af_ReadMode  = (accessMode == MODE_READ);
  225.             file->af_BlockSize = blockSize;
  226.  
  227.             /* initialize the ASyncFile structure. We do as much as we can here,
  228.              * in order to avoid doing it in more critical sections
  229.              *
  230.              * Note how the two buffers used are quad-longword aligned. This
  231.              * helps performance on 68040 systems with copyback cache. Aligning
  232.              * the data avoids a nasty side-effect of the 040 caches on DMA.
  233.              * Not aligning the data causes the device driver to have to do
  234.              * some magic to avoid the cache problem. This magic will generally
  235.              * involve flushing the CPU caches. This is very costly on an 040.
  236.              * Aligning things avoids the need for magic, at the cost of at
  237.              * most 15 bytes of ram.
  238.              */
  239.  
  240.             fh                     = BADDR(file->af_File);
  241.             file->af_Handler       = fh->fh_Type;
  242.             file->af_BufferSize    = bufferSize / 2;
  243.             file->af_Buffers[0]
  244.                 = (APTR)(((ULONG)file + sizeof(struct AsyncFile) + 15) & 0xfffffff0);
  245.             file->af_Buffers[1]
  246.                 = (APTR)((ULONG)file->af_Buffers[0] + file->af_BufferSize);
  247.             file->af_Offset        = file->af_Buffers[0];
  248.             file->af_CurrentBuf    = 0;
  249.             file->af_SeekOffset    = 0;
  250.             file->af_PacketPending = FALSE;
  251.  
  252.             /* this is the port used to get the packets we send out back.
  253.              * It is initialized to PA_IGNORE, which means that no signal is
  254.              * generated when a message comes in to the port. The signal bit
  255.              * number is initialized to SIGB_SINGLE, which is the special bit
  256.              * that can be used for one-shot signalling. The signal will never
  257.              * be set, since the port is of type PA_IGNORE. We'll change the
  258.              * type of the port later on to PA_SIGNAL whenever we need to wait
  259.              * for a message to come in.
  260.              *
  261.              * The trick used here avoids the need to allocate an extra signal
  262.              * bit for the port. It is quite efficient.
  263.              */
  264.  
  265.             file->af_PacketPort.mp_MsgList.lh_Head
  266.                 = (struct Node *)&file->af_PacketPort.mp_MsgList.lh_Tail;
  267.             file->af_PacketPort.mp_MsgList.lh_Tail     = NULL;
  268.             file->af_PacketPort.mp_MsgList.lh_TailPred
  269.                 = (struct Node *)&file->af_PacketPort.mp_MsgList.lh_Head;
  270.             file->af_PacketPort.mp_Node.ln_Type        = NT_MSGPORT;
  271.             file->af_PacketPort.mp_Flags               = PA_IGNORE;
  272.             file->af_PacketPort.mp_SigBit              = SIGB_SINGLE;
  273.             file->af_PacketPort.mp_SigTask             = FindTask(NULL);
  274.  
  275.             file->af_Packet.sp_Pkt.dp_Link          = &file->af_Packet.sp_Msg;
  276.             file->af_Packet.sp_Pkt.dp_Arg1          = fh->fh_Arg1;
  277.             file->af_Packet.sp_Pkt.dp_Arg3          = file->af_BufferSize;
  278.             file->af_Packet.sp_Pkt.dp_Res1          = 0;
  279.             file->af_Packet.sp_Pkt.dp_Res2          = 0;
  280.             file->af_Packet.sp_Msg.mn_Node.ln_Name  = (STRPTR)&file->af_Packet.sp_Pkt;
  281.             file->af_Packet.sp_Msg.mn_Node.ln_Type  = NT_MESSAGE;
  282.             file->af_Packet.sp_Msg.mn_Length        = sizeof(struct StandardPacket);
  283.  
  284.             if (accessMode == MODE_READ)
  285.             {
  286.                 /* if we are in read mode, send out the first read packet to
  287.                  * the file system. While the application is getting ready to
  288.                  * read data, the file system will happily fill in this buffer
  289.                  * with DMA transfers, so that by the time the application
  290.                  * needs the data, it will be in the buffer waiting
  291.                  */
  292.  
  293.                 file->af_Packet.sp_Pkt.dp_Type = ACTION_READ;
  294.                 file->af_BytesLeft             = 0;
  295.                 if (file->af_Handler)
  296.                     SendPacket(file,file->af_Buffers[0]);
  297.             }
  298.             else
  299.             {
  300.                 file->af_Packet.sp_Pkt.dp_Type = ACTION_WRITE;
  301.                 file->af_BytesLeft             = file->af_BufferSize;
  302.             }
  303.         }
  304.         else
  305.         {
  306.             Close(handle);
  307.         }
  308.     }
  309.  
  310.     return(file);
  311. }
  312.  
  313.  
  314. /*****************************************************************************/
  315.  
  316.  
  317. LONG CloseAsync(struct AsyncFile *file)
  318. {
  319. LONG result;
  320.  
  321.     if (file)
  322.     {
  323.         result = WaitPacket(file);
  324.         if (result >= 0)
  325.         {
  326.             if (!file->af_ReadMode)
  327.             {
  328.                 /* this will flush out any pending data in the write buffer */
  329.                 result = Write(file->af_File,
  330.                                file->af_Buffers[file->af_CurrentBuf],
  331.                                file->af_BufferSize - file->af_BytesLeft);
  332.             }
  333.         }
  334.  
  335.         Close(file->af_File);
  336.         FreeVec(file);
  337.     }
  338.     else
  339.     {
  340.         SetIoErr(ERROR_INVALID_LOCK);
  341.         result = -1;
  342.     }
  343.  
  344.     return(result);
  345. }
  346.  
  347.  
  348. /*****************************************************************************/
  349.  
  350.  
  351. LONG ReadAsync(struct AsyncFile *file, APTR buffer, LONG numBytes)
  352. {
  353. LONG totalBytes;
  354. LONG bytesArrived;
  355.  
  356.     totalBytes = 0;
  357.  
  358.     /* if we need more bytes than there are in the current buffer, enter the
  359.      * read loop
  360.      */
  361.  
  362.     while (numBytes > file->af_BytesLeft)
  363.     {
  364.         /* drain buffer */
  365.         CopyMem(file->af_Offset,buffer,file->af_BytesLeft);
  366.  
  367.         numBytes           -= file->af_BytesLeft;
  368.         buffer              = (APTR)((ULONG)buffer + file->af_BytesLeft);
  369.         totalBytes         += file->af_BytesLeft;
  370.         file->af_BytesLeft  = 0;
  371.  
  372.         bytesArrived = WaitPacket(file);
  373.         if (bytesArrived <= 0)
  374.         {
  375.             if (bytesArrived == 0)
  376.                 return(totalBytes);
  377.  
  378.             return(-1);
  379.         }
  380.  
  381.         /* ask that the buffer be filled */
  382.         SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
  383.  
  384.         if (file->af_SeekOffset > bytesArrived)
  385.             file->af_SeekOffset = bytesArrived;
  386.  
  387.         file->af_Offset      = (APTR)((ULONG)file->af_Buffers[file->af_CurrentBuf]
  388.                                    + file->af_SeekOffset);
  389.         file->af_CurrentBuf  = 1 - file->af_CurrentBuf;
  390.         file->af_BytesLeft   = bytesArrived - file->af_SeekOffset;
  391.         file->af_SeekOffset  = 0;
  392.     }
  393.  
  394.     CopyMem(file->af_Offset,buffer,numBytes);
  395.     file->af_BytesLeft -= numBytes;
  396.     file->af_Offset     = (APTR)((ULONG)file->af_Offset + numBytes);
  397.  
  398.     return (totalBytes + numBytes);
  399. }
  400.  
  401.  
  402. /*****************************************************************************/
  403.  
  404.  
  405. LONG ReadCharAsync(struct AsyncFile *file)
  406. {
  407. unsigned char ch;
  408.  
  409.     if (file->af_BytesLeft)
  410.     {
  411.         /* if there is at least a byte left in the current buffer, get it
  412.          * directly. Also update all counters
  413.          */
  414.  
  415.         ch = *(char *)file->af_Offset;
  416.         file->af_BytesLeft--;
  417.         file->af_Offset = (APTR)((ULONG)file->af_Offset + 1);
  418.  
  419.         return((LONG)ch);
  420.     }
  421.  
  422.     /* there were no characters in the current buffer, so call the main read
  423.      * routine. This has the effect of sending a request to the file system to
  424.      * have the current buffer refilled. After that request is done, the
  425.      * character is extracted for the alternate buffer, which at that point
  426.      * becomes the "current" buffer
  427.      */
  428.  
  429.     if (ReadAsync(file,&ch,1) > 0)
  430.         return((LONG)ch);
  431.  
  432.     /* We couldn't read above, so fail */
  433.  
  434.     return(-1);
  435. }
  436.  
  437.  
  438. /*****************************************************************************/
  439.  
  440.  
  441. LONG WriteAsync(struct AsyncFile *file, APTR buffer, LONG numBytes)
  442. {
  443. LONG totalBytes;
  444.  
  445.     totalBytes = 0;
  446.  
  447.     while (numBytes > file->af_BytesLeft)
  448.     {
  449.         /* this takes care of NIL: */
  450.         if (!file->af_Handler)
  451.         {
  452.             file->af_Offset    = file->af_Buffers[0];
  453.             file->af_BytesLeft = file->af_BufferSize;
  454.             return(numBytes);
  455.         }
  456.  
  457.         if (file->af_BytesLeft)
  458.         {
  459.             CopyMem(buffer,file->af_Offset,file->af_BytesLeft);
  460.  
  461.             numBytes   -= file->af_BytesLeft;
  462.             buffer      = (APTR)((ULONG)buffer + file->af_BytesLeft);
  463.             totalBytes += file->af_BytesLeft;
  464.         }
  465.  
  466.         if (WaitPacket(file) < 0)
  467.             return(-1);
  468.  
  469.         /* send the current buffer out to disk */
  470.         SendPacket(file,file->af_Buffers[file->af_CurrentBuf]);
  471.  
  472.         file->af_CurrentBuf = 1 - file->af_CurrentBuf;
  473.         file->af_Offset     = file->af_Buffers[file->af_CurrentBuf];
  474.         file->af_BytesLeft  = file->af_BufferSize;
  475.     }
  476.  
  477.     CopyMem(buffer,file->af_Offset,numBytes);
  478.     file->af_BytesLeft -= numBytes;
  479.     file->af_Offset     = (APTR)((ULONG)file->af_Offset + numBytes);
  480.  
  481.     return (totalBytes + numBytes);
  482. }
  483.  
  484.  
  485. /*****************************************************************************/
  486.  
  487.  
  488. LONG WriteCharAsync(struct AsyncFile *file, UBYTE ch)
  489. {
  490.     if (file->af_BytesLeft)
  491.     {
  492.         /* if there's any room left in the current buffer, directly write
  493.          * the byte into it, updating counters and stuff.
  494.          */
  495.  
  496.         *(UBYTE *)file->af_Offset = ch;
  497.         file->af_BytesLeft--;
  498.         file->af_Offset = (APTR)((ULONG)file->af_Offset + 1);
  499.  
  500.         /* one byte written */
  501.         return(1);
  502.     }
  503.  
  504.     /* there was no room in the current buffer, so call the main write
  505.      * routine. This will effectively send the current buffer out to disk,
  506.      * wait for the other buffer to come back, and then put the byte into
  507.      * it.
  508.      */
  509.  
  510.     return(WriteAsync(file,&ch,1));
  511. }
  512.  
  513.  
  514. /*****************************************************************************/
  515.  
  516.  
  517. LONG SeekAsync(struct AsyncFile *file, LONG position, BYTE mode)
  518. {
  519. LONG  current, target;
  520. LONG  minBuf, maxBuf;
  521. LONG  bytesArrived;
  522. LONG  diff;
  523. LONG  filePos;
  524. LONG  roundTarget;
  525. D_S(struct FileInfoBlock,fib);
  526.  
  527.     bytesArrived = WaitPacket(file);
  528.  
  529.     if (bytesArrived < 0)
  530.         return(-1);
  531.  
  532.     if (file->af_ReadMode)
  533.     {
  534.         /* figure out what the actual file position is */
  535.         filePos = Seek(file->af_File,OFFSET_CURRENT,0);
  536.         if (filePos < 0)
  537.         {
  538.             RecordSyncFailure(file);
  539.             return(-1);
  540.         }
  541.  
  542.         /* figure out what the caller's file position is */
  543.         current = filePos - (file->af_BytesLeft+bytesArrived);
  544.  
  545.         /* figure out the absolute offset within the file where we must seek to */
  546.         if (mode == MODE_CURRENT)
  547.         {
  548.             target = current + position;
  549.         }
  550.         else if (mode == MODE_START)
  551.         {
  552.             target = position;
  553.         }
  554.         else /* if (mode == MODE_END) */
  555.         {
  556.             if (!ExamineFH(file->af_File,fib))
  557.             {
  558.                 RecordSyncFailure(file);
  559.                 return(-1);
  560.             }
  561.  
  562.             target = fib->fib_Size + position;
  563.         }
  564.  
  565.         /* figure out what range of the file is currently in our buffers */
  566.         minBuf = current - (LONG)((ULONG)file->af_Offset -
  567.                      (ULONG)file->af_Buffers[1 - file->af_CurrentBuf]);
  568.         maxBuf = current + file->af_BytesLeft
  569.                      + bytesArrived;  /* WARNING: this is one too big */
  570.  
  571.         diff = target - current;
  572.  
  573.         if ((target < minBuf) || (target >= maxBuf))
  574.         {
  575.             /* the target seek location isn't currently in our buffers, so
  576.              * move the actual file pointer to the desired location, and then
  577.              * restart the async read thing...
  578.              */
  579.  
  580.             /* this is to keep our file reading block-aligned on the device.
  581.              * block-aligned reads are generally quite a bit faster, so it is
  582.              * worth the trouble to keep things aligned
  583.              */
  584.             roundTarget = (target / file->af_BlockSize) * file->af_BlockSize;
  585.  
  586.             if (Seek(file->af_File,roundTarget-filePos,OFFSET_CURRENT) < 0)
  587.             {
  588.                 RecordSyncFailure(file);
  589.                 return(-1);
  590.             }
  591.  
  592.             SendPacket(file,file->af_Buffers[0]);
  593.  
  594.             file->af_SeekOffset = target-roundTarget;
  595.             file->af_BytesLeft  = 0;
  596.             file->af_CurrentBuf = 0;
  597.         }
  598.         else if ((target < current) || (diff <= file->af_BytesLeft))
  599.         {
  600.             /* one of the two following things is true:
  601.              *
  602.              * 1. The target seek location is within the current read buffer,
  603.              * but before the current location within the buffer. Move back
  604.              * within the buffer and pretend we never got the pending packet,
  605.              * just to make life easier, and faster, in the read routine.
  606.              *
  607.              * 2. The target seek location is ahead within the current
  608.              * read buffer. Advance to that location. As above, pretend to
  609.              * have never received the pending packet.
  610.              */
  611.  
  612.             RequeuePacket(file);
  613.  
  614.             file->af_BytesLeft -= diff;
  615.             file->af_Offset     = (APTR)((ULONG)file->af_Offset + diff);
  616.         }
  617.         else
  618.         {
  619.             /* at this point, we know the target seek location is within
  620.              * the buffer filled in by the packet that we just received
  621.              * at the start of this function. Throw away all the bytes in the
  622.              * current buffer, send a packet out to get the async thing going
  623.              * again, readjust buffer pointers to the seek location, and return
  624.              * with a grin on your face... :-)
  625.              */
  626.  
  627.             diff -= file->af_BytesLeft;
  628.  
  629.             SendPacket(file,file->af_Buffers[1-file->af_CurrentBuf]);
  630.  
  631.             file->af_Offset
  632.                 = (APTR)((ULONG)file->af_Buffers[file->af_CurrentBuf] + diff);
  633.             file->af_CurrentBuf = 1 - file->af_CurrentBuf;
  634.             file->af_BytesLeft  = bytesArrived - diff;
  635.         }
  636.     }
  637.     else
  638.     {
  639.         if (Write(file->af_File,
  640.                   file->af_Buffers[file->af_CurrentBuf],
  641.                   file->af_BufferSize - file->af_BytesLeft) < 0)
  642.         {
  643.             RecordSyncFailure(file);
  644.             return(-1);
  645.         }
  646.  
  647.         /* this will unfortunately generally result in non block-aligned file
  648.          * access. We could be sneaky and try to resync our file pos at a
  649.          * later time, but we won't bother. Seeking in write-only files is
  650.          * relatively rare (except when writing IFF files with unknown chunk
  651.          * sizes, where the chunk size has to be written after the chunk data)
  652.          */
  653.  
  654.         current = Seek(file->af_File,position,mode);
  655.  
  656.         if (current < 0)
  657.         {
  658.             RecordSyncFailure(file);
  659.             return(-1);
  660.         }
  661.  
  662.         file->af_BytesLeft  = file->af_BufferSize;
  663.         file->af_CurrentBuf = 0;
  664.     }
  665.  
  666.     return(current);
  667. }
  668.