home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Graphics / ViewILBM / Source / asyncio.c next >
C/C++ Source or Header  |  1999-03-03  |  22KB  |  672 lines

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