/*
 * reserved Lock flushing routines.
 */

#include "vm.h"

/*
 * Flush the lock. This involves removing it from the reserved list (if it is
 * on it) locating the file position (extending the file if needed) and writing
 * the memory segment to the file.
 *
 * This action is altered only if the lock is marked READ_ONLY, in which case
 * the file write is skipped.
 *
 */
ULONG
VM_FlushLock (struct VM_Lock *VM_L) {
   BPTR VFile = VM_L->VM_C->VM_File ;
   ULONG Diff ;
   ULONG Err ;
   char *VBuf ;

   if (!(VM_L->VM_Flags & VM_READONLY)) {
      if (VM_L->VM_C->VM_Length >= VM_L->VM_FL->VM_Offset) {
         Err = Seek(VFile,VM_L->VM_FL->VM_Offset, OFFSET_BEGINNING) ;
         if (Err)
            return -1 ;
         }
      else {
         Err = Seek(VFile,VM_L->VM_C->VM_Length, OFFSET_BEGINNING) ;
         if (Err)
            return -1 ;

         Diff = VM_L->VM_FL->VM_Offset - VM_L->VM_C->VM_Length ;
         if (Diff > 0) {
            VBuf = (char *) TMemAlloc( Diff, MEMF_PUBLIC | MEMF_CLEAR ) ;

            if (!VBuf)
               return -1 ;

            Err = Write(VFile,VBuf,Diff) ;
            FreeTrackedItem(VBuf) ;

            if (Err < 0)
               return -1 ;

            VM_L->VM_C->VM_Length += Diff + VM_L->VM_FL->VM_Length ;
            }
         }

      Err = Write(VFile,VM_L->VM_Addr, VM_L->VM_FL->VM_Length) ;

      if (Err < 0)
         return -1 ;
      }

   if (VM_L->VM_Flags & VM_RESERVED) {
      VM_L->VM_C->VM_NumLocks -- ;
      Remove( (struct Node *) VM_L );
      }

   VM_L->VM_Flags &= ~(VM_INUSE | VM_RESERVED) ;
   FreeTrackedItem(VM_L->VM_Addr) ;
   return 0 ;
   }

ULONG
VM_FlushLockList(struct VM_Construct *VM_C) {

   ULONG Err ;

   while ( VM_C->VM_NumLocks ) {
      Err = VM_FlushLock((struct VM_Lock *)(VM_C->VM_LockList.mlh_TailPred)) ;
      if (Err)
         return -1 ;
      }

   return 0 ;
   }

ULONG
VM_ReadLock(struct VM_Lock *VM_L) {
   ULONG Err ;
   BPTR VFile = VM_L->VM_C->VM_File ;

   /*
    * Allocate the new memory and store the pointer in the lock.
    */
   VM_L->VM_Addr = (void *) TMemAlloc(VM_L->VM_FL->VM_Length,
                                         MEMF_PUBLIC|MEMF_CLEAR) ;
   if (VM_L->VM_Addr) {
      /*
       * If the file segment exists (Ie, file length > File Offset) then seek
       * to the correct place, and read the file.
       */
      if (VM_L->VM_C->VM_Length >= VM_L->VM_FL->VM_Offset) {
         Err = Seek(VFile,VM_L->VM_FL->VM_Offset, OFFSET_BEGINNING) ;
         if (Err) {
            FreeTrackedItem(VM_L->VM_Addr) ;
            return NULL ;
            }
         Err = Read(VFile,VM_L->VM_Addr, VM_L->VM_FL->VM_Length) ;
         if (Err < 0) {
            FreeTrackedItem(VM_L->VM_Addr) ;
            return NULL ;
            }
         }
      /*
       * Flags == IN_USE if the lock is in use.
       */
      VM_L->VM_Flags |= VM_INUSE ;

      return 0 ;
      }
   else
      return -1 ;
   }
