1651 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1651 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
//
 | 
						|
// FILESTOR.CPP
 | 
						|
//
 | 
						|
//  Source file for ArchiveLib 2.0
 | 
						|
//
 | 
						|
//  Copyright (c) Greenleaf Software, Inc. 1994-1996
 | 
						|
//  All Rights Reserved
 | 
						|
//
 | 
						|
// CONTENTS
 | 
						|
//
 | 
						|
//  ALFile::operator new()
 | 
						|
//  ALFile::ALFile()
 | 
						|
//  newALFile()
 | 
						|
//  ALFile::~ALFile()
 | 
						|
//  ALFile::LoadBuffer()
 | 
						|
//  ALFile::FlushBuffer()
 | 
						|
//  ALFile::Seek()
 | 
						|
//  ALFile::Open()
 | 
						|
//  ALFile::MakeTempName()
 | 
						|
//  ALFile::Create()
 | 
						|
//  ALFile::Close()
 | 
						|
//  ALFile::RenameToBackup()
 | 
						|
//  ALFile::Rename()
 | 
						|
//  ALFile::UnRename()
 | 
						|
//  ALFile::Delete()
 | 
						|
//  ALFile::Clone()
 | 
						|
//  ALFile::MakeDirectory()
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This file contains the C++ member functions to support class
 | 
						|
//  ALFile.  This class works very closely with the parent class,
 | 
						|
//  ALStorage, found in STORAGE.CPP.  You will find in many cases
 | 
						|
//  the virtual functions found here in the derived class call
 | 
						|
//  the same function in the parent class to help out with some
 | 
						|
//  of the work.
 | 
						|
//  We don't really do anything exciting in the WEP, it is just
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//  May 22, 1994  1.0A  : First release
 | 
						|
//
 | 
						|
//  July 7, 1994  1.0B  : Had to make a lot of changes to support file
 | 
						|
//                        management under UNIX.
 | 
						|
//
 | 
						|
 | 
						|
#include "arclib.h"
 | 
						|
#if !defined( AL_IBM )
 | 
						|
#pragma hdrstop
 | 
						|
#endif
 | 
						|
 | 
						|
#include <fcntl.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <time.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#if defined( AL_OS2 )
 | 
						|
  #define INCL_DOSFILEMGR
 | 
						|
  #include <os2.h>
 | 
						|
  #include <io.h>
 | 
						|
  #if defined( AL_BORLAND )
 | 
						|
    #include <dir.h>
 | 
						|
  #else
 | 
						|
    #include <direct.h>
 | 
						|
  #endif
 | 
						|
#else
 | 
						|
  #include <io.h>
 | 
						|
  #include <dos.h>
 | 
						|
  #include <direct.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include "filestor.h"
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::operator new()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Memory allocator used when ArchiveLib resides in a 16 bit DLL.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  void * ALArchive::operator new( size_t size )
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  size  :  The number of bytes that the compiler has decided will be
 | 
						|
//           necessary to construct a new ALFile object.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  When using a DLL, it is easy to get into a dangerous situation when
 | 
						|
//  creating objects whose ctor and dtor are both in the DLL.  The problem
 | 
						|
//  arises because when you create an object using new, the memory for
 | 
						|
//  the object will be allocated from the EXE.  However, when you destroy
 | 
						|
//  the object using delete, the memory is freed inside the DLL.  Since
 | 
						|
//  the DLL doesn't really own that memory, bad things can happen.
 | 
						|
//
 | 
						|
//  But, you say, won't the space just go back to the Windows heap regardless
 | 
						|
//  of who tries to free it?  Maybe, but maybe not.  If the DLL is using
 | 
						|
//  a subsegment allocation scheme, it might do some sort of local free
 | 
						|
//  before returning the space to the windows heap.  That is the point where
 | 
						|
//  you could conceivably cook your heap.
 | 
						|
//
 | 
						|
//  By providing our own version of operator new inside this class, we
 | 
						|
//  ensure that all memory allocation for the class will be done from
 | 
						|
//  inside the DLL, not the EXE calling the DLL.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  A pointer to some memory that should have been pulled out of the
 | 
						|
//  heap for the DLL.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//  February 14, 1996  2.0A : New release
 | 
						|
//
 | 
						|
 | 
						|
#if defined( AL_BUILDING_DLL )
 | 
						|
 | 
						|
void AL_DLL_FAR * AL_PROTO
 | 
						|
ALFile::operator new( size_t size )  /* Tag internal function */
 | 
						|
{
 | 
						|
    return ::new char[ size ];
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::ALFile()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++  C  VB  Delphi
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  The ALFile constructor.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  ALFile::ALFile( const char *file_name = "",
 | 
						|
//                  int buffer_size = 4096,
 | 
						|
//                  ALCase name_case = AL_LOWER );
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  hALStorage newALFile( char *file_name );
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  Declare Function newALFile Lib "AL20LW" (ByVal file_name$) As Long
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  function newALFile( file_name : PChar ) : hALStorage;
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  file_name    : The initial file name of the ALFile object you are
 | 
						|
//                 creating.  The C++ version has a default argument,
 | 
						|
//                 which is a blank string, which will get converted to a
 | 
						|
//                 temporary name before opening the actual disk file.
 | 
						|
//
 | 
						|
//  buffer_size  : The size of the object's I/O buffer.  The default of 4096
 | 
						|
//                 should give very good performance.  Note that C/VB/Delphi
 | 
						|
//                 users don't get any choice about the buffer size!  This
 | 
						|
//                 was done strictly in order to cut back on confusion.
 | 
						|
//
 | 
						|
//  name_case    : This parameter determines whether the file names will
 | 
						|
//                 always be converted to upper case, lower case, or left
 | 
						|
//                 in mixed case.  Under MS-DOS, you shouldn't use mixed
 | 
						|
//                 case, because the O/S file naming convention is case
 | 
						|
//                 insensitive.  ArchiveLib will think "TEMP.BAK" and
 | 
						|
//                 "temp.bak" are different, when they really aren't.
 | 
						|
//
 | 
						|
//                 Once again, C/VB/Delphi users are stuck with the default.
 | 
						|
//
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This constructor is used to create a new ALFile object, which will
 | 
						|
//  usually be treated as an ALStorage object by ArchiveLib functions.
 | 
						|
//  It is important to note that not much happens during construction of
 | 
						|
//  this object, the real activity happens after you call the Open()
 | 
						|
//  function.  Just creating this object *does not* create a file on disk!
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  Nothing, this is a constructor.  The C/VB/Delphi translation routines
 | 
						|
//  return a handle pointing to the newly created ALFile object.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::ALStorage()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//  February 14, 1996  2.0A : New release
 | 
						|
//
 | 
						|
 | 
						|
AL_PROTO
 | 
						|
ALFile::ALFile( const char AL_DLL_FAR *file_name /* = "" */,  /* Tag public function */
 | 
						|
                         int buffer_size /* = 4096 */,
 | 
						|
                         ALCase name_case /* = AL_LOWER */)
 | 
						|
// Note: if non-msdos, change case parameter to AL_MIXED
 | 
						|
    : ALStorage( file_name, buffer_size, AL_FILE_OBJECT, name_case ) {
 | 
						|
    miHandle = -1;
 | 
						|
}
 | 
						|
 | 
						|
#if !defined( AL_NO_C )
 | 
						|
 | 
						|
extern "C" AL_LINKAGE hALStorage AL_FUNCTION
 | 
						|
newALFile( char AL_DLL_FAR *file_name )  /* Tag public function */
 | 
						|
{
 | 
						|
    return (hALStorage) new ALFile( file_name );
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::~ALFile()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  The ALFile destructor.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  ALFile::~ALFile()
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use deleteALStorage();
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use deleteALStorage();
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use deleteALStorage();
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  The destructor for an ALFile object doesn't have to do much work.
 | 
						|
//  The base class destructor will take care of freeing the I/O buffer,
 | 
						|
//  and any other loose ends.  All we have to do here is make sure
 | 
						|
//  the file gets closed, and that its buffers get flushed to the disk
 | 
						|
//  file.
 | 
						|
//
 | 
						|
//  Note that in debug mode, the destructor also checks this for the
 | 
						|
//  correct class type.  This helps flag erroneous or duplicated
 | 
						|
//  destructor calls.
 | 
						|
//
 | 
						|
//  C/VB/Delphi users don't have a specific function to call this guy.
 | 
						|
//  Instead, the call deleteALStorage(), which will in turn call the
 | 
						|
//  virtual destructor.  If it's an ALFile object, it will get here
 | 
						|
//  one way or another.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  Nothing, it's a dtor!
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::~ALStorage(), ALFile::ALFile()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New release
 | 
						|
//
 | 
						|
 | 
						|
AL_PROTO
 | 
						|
ALFile::~ALFile()  /* Tag public function */
 | 
						|
{
 | 
						|
    AL_ASSERT( GoodTag(), "~ALFile: attempting to delete invalid object" );
 | 
						|
    if ( miHandle != -1 )
 | 
						|
        Close();
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::LoadBuffer()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Load a new batch of data from the file into the local buffer.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::LoadBuffer( long address )
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageLoadBuffer().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageLoadBuffer().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageLoadBuffer().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  address  : The long offset into the physical file.  A seek/read
 | 
						|
//             combination will be executed at this location,
 | 
						|
//             so that subsequent calls to read data will start at
 | 
						|
//             the given address.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is used in the library whenever a byte needs to be read
 | 
						|
//  that isn't present in the current I/O buffer.  It has to use
 | 
						|
//  the C RTL function lseek() to go to the correct position in the library.
 | 
						|
//  If that works, it uses the C RTL function read() to read in an I/O
 | 
						|
//  buffer full of data.
 | 
						|
//
 | 
						|
//  After that operation is performed, muReadIndex is set to 0, indicating
 | 
						|
//  that the next read from the I/O buffer will take place at location 0.
 | 
						|
//  mlFilePointer is set to 'address' plus the number of bytes read, so
 | 
						|
//  we know where the next read from the file will take place.  And
 | 
						|
//  muBufferValidData is set to the count of bytes read in from this
 | 
						|
//  location.  That lets us know how far we can read in the I/O buffer
 | 
						|
//  before we run out of space.
 | 
						|
//
 | 
						|
//  Note that if CRC checking has been turned on, we will update the
 | 
						|
//  current working CRC value with the new data that has been read
 | 
						|
//  in from the buffer.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_SUCCESS, AL_SEEK_ERROR, AL_END_OF_FILE, or possibly another
 | 
						|
//  error code < AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::LoadBuffer(), ALFile::FlushBuffer(), ALStorage::ReadChar()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::LoadBuffer( long address )  /* Tag public function */
 | 
						|
{
 | 
						|
    if ( mStatus < AL_SUCCESS )
 | 
						|
        return mStatus;
 | 
						|
    if ( mlFilePointer != address ) {
 | 
						|
        long result = lseek( miHandle, address, SEEK_SET );
 | 
						|
        if ( result == -1L )
 | 
						|
            return mStatus.SetError( AL_SEEK_ERROR,
 | 
						|
                                     "Seek failure on %s.  errno = %d",
 | 
						|
                                     mName.GetName(),
 | 
						|
                                     errno );
 | 
						|
    }
 | 
						|
    int result = read( miHandle, mpcBuffer, muBufferSize );
 | 
						|
    if ( result == 0 )
 | 
						|
        return AL_END_OF_FILE;
 | 
						|
    if ( result < 0 )
 | 
						|
        return mStatus.SetError( AL_READ_ERROR,
 | 
						|
                                   "Read failure on %s.  errno = %d",
 | 
						|
                                   mName.GetName(),
 | 
						|
                                   errno );
 | 
						|
    if ( miUpdateCrcFlag )
 | 
						|
        UpdateCrc( result );
 | 
						|
    muReadIndex = 0; //Reading can resume at this location in the I/O buffer
 | 
						|
    mlFilePointer += result;
 | 
						|
    muBufferValidData = result;
 | 
						|
    YieldTime();
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::FlushBuffer()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Flush the internal read/write buffer.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::FlushBuffer()
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageFlushBuffer().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageFlushBuffer().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageFlushBuffer();
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is the counterpart to LoadBuffer(). It gets called
 | 
						|
//  when a write operation is poised to overflow the I/O buffer.  This
 | 
						|
//  means we need to flush the buffer out to disk, then reset some
 | 
						|
//  data members.
 | 
						|
//
 | 
						|
//  Unlike LoadBuffer(), this function doesn't have an address argument,
 | 
						|
//  so we don't have to perform a seek().  Instead, the data will be
 | 
						|
//  written out to the current position of the file pointer.  If the
 | 
						|
//  write is successful, muWriteIndex is set to 0, indicating that the
 | 
						|
//  next write to the I/O buffer can go to position 0.  mlFilePointer is
 | 
						|
//  incremented by the length of the write, so we know where the next read
 | 
						|
//  or write will occur.  Finally, muBufferValidData is set to 0, indicating
 | 
						|
//  that there is no data in the I/O buffer that has been written, and
 | 
						|
//  there is no data that can be read.
 | 
						|
//
 | 
						|
//  C/VB/Delphi programmers don't have a direct translation function for
 | 
						|
//  this call.  Instead, the call ALStorageLoadBuffer(), which in turn
 | 
						|
//  will use the virtual function calling mechanism to come here.  At least
 | 
						|
//  if 'this' is an ALFile object, that is.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  An integer status value, AL_SUCCESS, AL_WRITE_ERROR, or possibly some
 | 
						|
//  status code < AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::FlushBuffer(), ALFile::LoadBuffer()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::FlushBuffer()  /* Tag public function */
 | 
						|
{
 | 
						|
    if ( mStatus < 0 )
 | 
						|
        return mStatus;
 | 
						|
    if ( muWriteIndex != 0 ) {
 | 
						|
        if ( miUpdateCrcFlag )
 | 
						|
            UpdateCrc( muWriteIndex );
 | 
						|
        int result = write( miHandle, mpcBuffer, muWriteIndex );
 | 
						|
        if ( (unsigned int) result != muWriteIndex )
 | 
						|
            return mStatus.SetError( AL_WRITE_ERROR,
 | 
						|
                                     "Write failure on %s.  "
 | 
						|
                                     "result = %d, errno = %d",
 | 
						|
                                     mName.GetName(),
 | 
						|
                                     result,
 | 
						|
                                     errno );
 | 
						|
        muWriteIndex = 0;
 | 
						|
        mlFilePointer += result;
 | 
						|
    }
 | 
						|
    muReadIndex = 0;
 | 
						|
    muBufferValidData = 0;
 | 
						|
    YieldTime();
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Seek()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Seek to a given position in an input file.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::Seek( long address )
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageSeek().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageSeek().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageSeek().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  address  :  The address in the physical file to seek to.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This is a function the user can call to position the read/write pointer
 | 
						|
//  to a new location in the disk file.  If there is any data that has been
 | 
						|
//  written to the I/O buffer, it gets flushed first.  After that, we do
 | 
						|
//  a seek, and update mlFilePointer to reflect the new reality.  Note that
 | 
						|
//  the other important data members will have been updated by FlushBuffer().
 | 
						|
//
 | 
						|
//  And no, this guy doesn't do a LoadBuffer().  Which is fine if you are
 | 
						|
//  going to do a bunch of writes afterwards.  If you are going to read data
 | 
						|
//  immediately after Seek(), you would have been better of calling
 | 
						|
//  LoadBuffer().
 | 
						|
//
 | 
						|
//  C/VB/Delphi programmers don't have a direct translation function for
 | 
						|
//  this call.  Instead, they should call ALStorageSeek(), which in turn
 | 
						|
//  will use the virtual function calling mechanism to come here.  At least
 | 
						|
//  if 'this' is an ALFile object, that is.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_SUCCESS, AL_SEEK_ERROR, or possibly some other status code < AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::Seek(), ALFile::Tell()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::Seek( long address )  /* Tag public function */
 | 
						|
{
 | 
						|
    FlushBuffer();
 | 
						|
    if ( mStatus < 0 )
 | 
						|
        return mStatus;
 | 
						|
    if ( mlFilePointer != address ) {
 | 
						|
        long result = lseek( miHandle, address, SEEK_SET );
 | 
						|
        if ( result == -1L )
 | 
						|
            return mStatus.SetError( AL_SEEK_ERROR,
 | 
						|
                                     "Seek failure on %s.  errno = %d",
 | 
						|
                                     mName.GetName(),
 | 
						|
                                     errno );
 | 
						|
    }
 | 
						|
    mlFilePointer = address;
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Open()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Open an ALFile object.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::Open()
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageOpen().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageOpen().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageOpen().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This is an important function, because it converts the ALFile
 | 
						|
//  object from a dinky little unimportant object, to a big massive
 | 
						|
//  thing that is ready to do serious work.
 | 
						|
//
 | 
						|
//  The first thing we do here is see if we can open the file.  We try
 | 
						|
//  to open it with READ/WRITE privileges, but we give up and drop back
 | 
						|
//  to READ only if that doesn't work out.
 | 
						|
//
 | 
						|
//  We then call the base class ALStorage::Open() who takes care of
 | 
						|
//  allocating buffers and initializing data members.
 | 
						|
//
 | 
						|
//  Finally, we have to get the protection attributes and time date
 | 
						|
//  stamps for the file.  After those are stored off, the file is ready
 | 
						|
//  for abuse.
 | 
						|
//
 | 
						|
//  C/VB/Delphi programmers don't have a direct translation function for
 | 
						|
//  this call.  Instead, they should call ALStorageOpen(), which in turn
 | 
						|
//  will use the virtual function calling mechanism to come here.  At least
 | 
						|
//  if 'this' is an ALFile object, that is.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_CANT_OPEN_FILE, AL_SUCCESS, or possibly some other error code
 | 
						|
//  < AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALFile::Create(), ALStorage::Open()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::Open()  /* Tag public function */
 | 
						|
{
 | 
						|
    if ( mStatus < AL_SUCCESS )
 | 
						|
        return mStatus;
 | 
						|
    miHandle = open( mName, O_BINARY | O_RDWR );
 | 
						|
 | 
						|
    if ( miHandle == -1 && errno == EACCES )
 | 
						|
        miHandle = open( mName, O_BINARY | O_RDONLY );
 | 
						|
    if ( miHandle == -1 )
 | 
						|
        return mStatus.SetError( AL_CANT_OPEN_FILE,
 | 
						|
                                 "File open failure.  Open of %s returned "
 | 
						|
                                 "errno = %d",
 | 
						|
                                 mName.GetName(),
 | 
						|
                                 errno );
 | 
						|
 | 
						|
    ALStorage::Open();
 | 
						|
    struct stat buf;
 | 
						|
    struct tm AL_DLL_FAR *tblock;
 | 
						|
    if ( stat( mName, &buf ) == -1 )
 | 
						|
        return mStatus.SetError( AL_CANT_OPEN_FILE,
 | 
						|
                                 "Couldn't get time, date, and size "
 | 
						|
                                 "information for %s.  errno = %d.",
 | 
						|
                                 mName.GetName(),
 | 
						|
                                 errno );
 | 
						|
    mlSize = buf.st_size;
 | 
						|
    tblock = localtime( &buf.st_mtime );
 | 
						|
    mTimeDate.SetTimeDate( tblock );
 | 
						|
#if defined( AL_WINDOWS ) && defined( AL_FLAT_MODEL )
 | 
						|
    TIME_ZONE_INFORMATION tzi;
 | 
						|
    GetTimeZoneInformation( &tzi );
 | 
						|
    long result = mTimeDate.GetUnixTime();
 | 
						|
    result -= tzi.Bias * 60;
 | 
						|
    mTimeDate.SetTimeDate( result );
 | 
						|
#endif
 | 
						|
    ReadAttributesFromFileSys();
 | 
						|
    if ( mStatus < 0 )
 | 
						|
        return mStatus;
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::MakeTempName( int i )
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Private function to make a temporary filename.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  void ALFile::MakeTempName( int i )
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, this is an internal C++ member function.
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, this is an internal C++ member function.
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, this is an internal C++ member function.
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  i    : A numeric argument that can somehow be incorporated into
 | 
						|
//         the temporary file name.  Create() will call this function
 | 
						|
//         while incrementing this number in an attempt to find a unique
 | 
						|
//         name.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is called by Create() and other functions when they
 | 
						|
//  decide they need to cook up a temporary file name.  The single parameter
 | 
						|
//  i is incremented by the calling program so that repeated calls should
 | 
						|
//  eventually produce a unique name.
 | 
						|
//
 | 
						|
//  All this function does to create that unique name is perform a sprintf()
 | 
						|
//  into a buffer using a simple template.  The result is copied into the
 | 
						|
//  mName member, and is ready to be tried out.
 | 
						|
//
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  Nothing.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALFile::Create()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
void AL_PROTO
 | 
						|
ALFile::MakeTempName( int i )  /* Tag protected function */
 | 
						|
{
 | 
						|
    char name[ 21 ];
 | 
						|
 | 
						|
    sprintf( name, "~al~%03d.tmp", i );
 | 
						|
    mName = name;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Create()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Create a new physical file using an ALFile object.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::Create( long )
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageCreate().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageCreate().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageCreate().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is used to create a new file storage object.  Since
 | 
						|
//  we are creating a new object, we must be able to open it with read
 | 
						|
//  access.  We will also rudely obliterate any existing file.
 | 
						|
//
 | 
						|
//  The first thing we do here is call the base class Create() function.
 | 
						|
//  It takes care of setting up the I/O buffer and initializing the
 | 
						|
//  data members used to support the class.
 | 
						|
//
 | 
						|
//  Since this is a virtual function in a derived class, C/VB/Delphi
 | 
						|
//  programmers aren't going to be able to call it directly.  They
 | 
						|
//  will instead call ALStorageCreate(), which will wind up here
 | 
						|
//  via the virtual function mechanism.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_SUCCESS, AL_CANT_OPEN_FILE, or possibly some other error code
 | 
						|
//  < AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::Create(), ALFile::Open()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::Create( long )  /* Tag public function */
 | 
						|
{
 | 
						|
    ALStorage::Create();
 | 
						|
    if ( mStatus < AL_SUCCESS )
 | 
						|
        return mStatus;
 | 
						|
    char AL_DLL_FAR *p = mName;
 | 
						|
    int i;
 | 
						|
//
 | 
						|
// We don't try to make a directory for unnamed temp files.
 | 
						|
//
 | 
						|
    if ( p == 0 || p[ 0 ] == 0 ) {
 | 
						|
        for ( i = 0 ; i < 999 ; i++ ) {
 | 
						|
            MakeTempName( i );
 | 
						|
            miHandle = open( mName,
 | 
						|
                             O_CREAT | O_RDWR | O_BINARY | O_EXCL,
 | 
						|
                             S_IREAD | S_IWRITE );
 | 
						|
            if ( miHandle != -1 )
 | 
						|
                break;
 | 
						|
            else if ( errno != EEXIST && errno != EACCES ) {
 | 
						|
                mStatus.SetError( AL_CANT_OPEN_FILE,
 | 
						|
                                  "Temporary file creation failure.  "
 | 
						|
                                  "Open of %s returned errno = %d",
 | 
						|
                                  mName.GetName(),
 | 
						|
                                  errno );
 | 
						|
                mName = "";
 | 
						|
                return AL_CANT_OPEN_FILE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ( i == 1000 ) {
 | 
						|
            mStatus.SetError( AL_CANT_OPEN_FILE,
 | 
						|
                              "Temporary file creation failure.  "
 | 
						|
                              "Tried 1000 times to open %s "
 | 
						|
                              "(or a name something like that).",
 | 
						|
                              mName.GetName() );
 | 
						|
            mName = "";
 | 
						|
            return AL_CANT_OPEN_FILE;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        miHandle = open( mName,
 | 
						|
                         O_CREAT | O_RDWR | O_BINARY | O_TRUNC,
 | 
						|
                         S_IREAD | S_IWRITE );
 | 
						|
//
 | 
						|
// Handle failure to make directories here
 | 
						|
//
 | 
						|
        if ( miHandle == -1 &&
 | 
						|
            errno == ENOENT &&
 | 
						|
            ( strchr( mName, '/' ) || strchr( mName, '\\' ) ) ) {
 | 
						|
            if ( MakeDirectory() ) {
 | 
						|
                miHandle = open( mName,
 | 
						|
                                 O_CREAT | O_RDWR | O_BINARY | O_TRUNC,
 | 
						|
                                 S_IREAD | S_IWRITE );
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ( miHandle == -1 && mAttributes.Directory() == 0 )
 | 
						|
        return mStatus.SetError( AL_CANT_OPEN_FILE,
 | 
						|
                                 "File creation failure.  "
 | 
						|
                                 "Open of %s returned errno = %d",
 | 
						|
                                 mName.GetName(),
 | 
						|
                                 errno );
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Close()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Close the physical file associated with an ALFile object.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::Close()
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageClose().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageClose().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageClose().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is called when you are done accessing a file, and want
 | 
						|
//  to free up its resources.  The first thing it does is check to see
 | 
						|
//  if the file was ever actually opened.  If it was, we flush the output
 | 
						|
//  buffer, then calculate and store the file length.  Finally, we close
 | 
						|
//  the disk file, then call the base class Close() function to clean up
 | 
						|
//  the buffers and deal with other miscellaneous dirty work.
 | 
						|
//
 | 
						|
//  Since this is a virtual function in a derived class, C/VB/Delphi
 | 
						|
//  programmers aren't going to be able to call it directly.  They
 | 
						|
//  will instead call ALStorageClose(), which will wind up here
 | 
						|
//  via the virtual function mechanism.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  Any status code, hopefully AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::Close(), ALFile::Create(), ALFile::Open()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
//
 | 
						|
// Note:  eventually I need to move the O/S specific code here into
 | 
						|
//        cpp_fs.nt, cpp_fs.os2, and cpp_fs.dos.
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::Close()  /* Tag public function */
 | 
						|
{
 | 
						|
    if ( miHandle == -1 )
 | 
						|
        return mStatus;
 | 
						|
    FlushBuffer();
 | 
						|
    mlSize = filelength( miHandle );
 | 
						|
    if ( miCreated && mTimeDate.Valid() ) {
 | 
						|
#if defined( AL_WIN32 )
 | 
						|
        TIME_ZONE_INFORMATION tzi;
 | 
						|
        GetTimeZoneInformation( &tzi );
 | 
						|
        long result = mTimeDate.GetUnixTime();
 | 
						|
        result += tzi.Bias * 60;
 | 
						|
        mTimeDate.SetTimeDate( result );
 | 
						|
        FILETIME FileTime;
 | 
						|
        LPFILETIME lpFileTime = &FileTime;
 | 
						|
        WORD wDosDate = (WORD) mTimeDate.GetDosDate();
 | 
						|
        WORD wDosTime = (WORD) mTimeDate.GetDosTime();
 | 
						|
        DosDateTimeToFileTime( wDosDate, wDosTime, lpFileTime );
 | 
						|
#  if defined( AL_WATCOM )
 | 
						|
        SetFileTime( (HANDLE) _os_handle( miHandle ), NULL, NULL, lpFileTime );
 | 
						|
#  else
 | 
						|
        SetFileTime( (HANDLE) _get_osfhandle( miHandle ), NULL, NULL, lpFileTime );
 | 
						|
#  endif
 | 
						|
#elif defined( AL_OS2 )
 | 
						|
// going to do it all after the file is closed
 | 
						|
#else
 | 
						|
        _dos_setftime( miHandle,
 | 
						|
                       mTimeDate.GetDosDate(),
 | 
						|
                       mTimeDate.GetDosTime() );
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    close( miHandle );
 | 
						|
    miHandle = -1;
 | 
						|
    ALStorage::Close();
 | 
						|
    if ( miCreated && mTimeDate.Valid() )
 | 
						|
        WriteAttributesToFileSys();
 | 
						|
    return mStatus;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::RenameToBackup()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Rename the physical file on disk to a suitable backup name.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::RenameToBackup( int delete_on_clash = 1 );
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageRenameToBackup().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageRenameToBackup().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageRenameToBackup().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  delete_on_clash  : If this flag is set, it means that we will overwrite
 | 
						|
//                     an existing file with this file if the names clash.
 | 
						|
//                     For example, if I am renaming TEMP.DAT to TEMP.BAK,
 | 
						|
//                     and a TEMP.BAK already exists, I will delete it
 | 
						|
//                     before renaming if this arg is set.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is a quick way to rename a storage object. The new
 | 
						|
//  name created is the default name, which usually means changing the
 | 
						|
//  file extension to ".BAK", from whatever it was.
 | 
						|
//
 | 
						|
//  You don't see it here, but both the mName member and the physical file
 | 
						|
//  name are updated.  That all happens in the Rename() function.
 | 
						|
//
 | 
						|
//  Since this is a virtual function in a derived class, C/VB/Delphi
 | 
						|
//  programmers aren't going to be able to call it directly.  They
 | 
						|
//  will instead call ALStorageRenameToBackup(), which will wind up here
 | 
						|
//  via the virtual function mechanism.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_SUCCESS or AL_RENAME_ERROR.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALFile::Rename(), ALStorage::RenameToBackup()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::RenameToBackup( int delete_on_clash /* = 1 */ )  /* Tag public function */
 | 
						|
{
 | 
						|
    mName.ChangeExtension();
 | 
						|
    return Rename( 0, delete_on_clash );
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Rename()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Rename an existing file on disk.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::Rename( const char *new_name = 0,
 | 
						|
//                      int delete_on_clash = 1 );
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageRename().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageRename().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageRename().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  new_name         : A character pointer to a new file name.  If a name is
 | 
						|
//                     defined here, the file is renamed to this new value.
 | 
						|
//                     If this value is 0, it means that we expect that
 | 
						|
//                     the mName member has already been updated with a
 | 
						|
//                     new name.  In this case, the old name of the
 | 
						|
//                     file is renamed to the new name.
 | 
						|
//
 | 
						|
//  delete_on_clash  : If this flag is set, it means that we will overwrite
 | 
						|
//                     an existing file with this file if the names clash.
 | 
						|
//                     For example, if I am renaming TEMP.DAT to TEMP.BAK,
 | 
						|
//                     and a TEMP.BAK already exists, I will delete it
 | 
						|
//                     before renaming if this arg is set.
 | 
						|
//
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This virtual function provides a way to rename a storage object's
 | 
						|
//  physical implementation.  It first updates the mName member if a
 | 
						|
//  new_name argument is provided.  After that, we unlink the clash file
 | 
						|
//  if one exists, then do a simple rename of mName.mszOldName to
 | 
						|
//  new_name.
 | 
						|
//
 | 
						|
//  Note that this function does a lot of error checking in debug mode.
 | 
						|
//  It also does a little error checking in release mode.
 | 
						|
//
 | 
						|
//  Since this is a virtual function in a derived class, C/VB/Delphi
 | 
						|
//  programmers aren't going to be able to call it directly.  They
 | 
						|
//  will instead call ALStorageRename(), which will wind up here
 | 
						|
//  via the virtual function mechanism.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_SUCCESS or AL_RENAME_ERROR.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::Rename( const char AL_DLL_FAR *new_name /* = 0 */,  /* Tag public function */
 | 
						|
                int delete_on_clash /* = 1 */ )
 | 
						|
{
 | 
						|
    AL_ASSERT( miHandle == -1, "Rename: attempting to rename open file" );
 | 
						|
    AL_ASSERT( mName.GetName() != 0, "Rename: attempting to rename file with null name" );
 | 
						|
    AL_ASSERT( strlen( mName ) > 0, "Rename: attempting to rename file with 0 length name" );
 | 
						|
 | 
						|
    int status;
 | 
						|
    const char AL_DLL_FAR *real_old_name;
 | 
						|
    const char AL_DLL_FAR *real_new_name;
 | 
						|
    if ( new_name ) {
 | 
						|
        real_old_name = mName.GetSafeName();
 | 
						|
        real_new_name = new_name;
 | 
						|
    } else {
 | 
						|
        real_old_name = mName.GetSafeOldName();
 | 
						|
        real_new_name = mName.GetSafeName();
 | 
						|
    }
 | 
						|
#if !defined( AL_WIN32 )
 | 
						|
    const char AL_DLL_FAR *p = strrchr( real_new_name, '.' );
 | 
						|
    if ( p && strlen( p ) > 4 )
 | 
						|
        return mStatus.SetError( AL_RENAME_ERROR,
 | 
						|
                            "Error trying to rename %s.  It has a long "
 | 
						|
                            "extension, which could lead to inadvertent "
 | 
						|
                            "deletion of a file when trying to rename.",
 | 
						|
                            real_old_name );
 | 
						|
#endif
 | 
						|
    if ( delete_on_clash ) {
 | 
						|
        if ( mName.mCase == AL_MIXED )
 | 
						|
            status = strcmp( real_new_name, real_old_name );
 | 
						|
        else
 | 
						|
            status = stricmp( real_new_name, real_old_name );
 | 
						|
        if ( status == 0 )
 | 
						|
            return mStatus.SetError( AL_RENAME_ERROR,
 | 
						|
                                     "Error attempting to rename %s to %s.  "
 | 
						|
                                     "Can't rename to the same name!",
 | 
						|
                                     real_new_name,
 | 
						|
                                     real_old_name );
 | 
						|
        status = unlink( real_new_name );
 | 
						|
        if ( status != 0 && errno != ENOENT )
 | 
						|
            return mStatus.SetError( AL_RENAME_ERROR,
 | 
						|
                                     "Error deleting %s before renaming %s.  "
 | 
						|
                                     "errno = %d",
 | 
						|
                                     real_new_name,
 | 
						|
                                     real_old_name,
 | 
						|
                                     errno );
 | 
						|
    }
 | 
						|
    status = rename( real_old_name, real_new_name );
 | 
						|
    if ( status != 0 )
 | 
						|
        return mStatus.SetError( AL_RENAME_ERROR,
 | 
						|
                                 "Error renaming %s to %s.  errno = %d",
 | 
						|
                                 real_old_name,
 | 
						|
                                 real_new_name,
 | 
						|
                                 errno );
 | 
						|
    if ( new_name != 0 )
 | 
						|
        mName = new_name;
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::UnRename()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Undo the renaming of a file.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::UnRename( int delete_on_clash = 1 );
 | 
						|
///
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageUnRename().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageUnRename().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageUnRename().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  delete_on_clash  : If this flag is set, it means that we will overwrite
 | 
						|
//                     an existing file with this file if the names clash.
 | 
						|
//                     For example, if I am renaming TEMP.BAK to TEMP.DAT,
 | 
						|
//                     and a TEMP.DAT already exists, I will delete it
 | 
						|
//                     before renaming if this arg is set.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This virtual function provides a way to undo a previous renaming of
 | 
						|
//  a storage object's physical name.  We can do this because the mName
 | 
						|
//  member of ALStorage keeps track both of the current name of the file,
 | 
						|
//  and the old name.  In this case, we just rename the current name to
 | 
						|
//  the old name.  Then we update the mName member so it is accurate.
 | 
						|
//
 | 
						|
//  Note that this function does a lot of error checking in debug mode.
 | 
						|
//  It also does a little error checking in release mode.
 | 
						|
//
 | 
						|
//  Since this is a virtual function in a derived class, C/VB/Delphi
 | 
						|
//  programmers aren't going to be able to call it directly.  They
 | 
						|
//  will instead call ALStorageRename(), which will wind up here
 | 
						|
//  via the virtual function mechanism.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_SUCCESS or AL_RENAME_ERROR.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALStorage::UnRename(), ALFile::Rename()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::UnRename( int delete_on_clash /* = 1 */ )  /* Tag public function */
 | 
						|
{
 | 
						|
    AL_ASSERT( miHandle == -1, "UnRename: attempting to rename open file" );
 | 
						|
    AL_ASSERT( mName.GetName() != 0, "UnRename: attempting to rename file with null name" );
 | 
						|
    AL_ASSERT( mName.GetOldName() != 0, "UnRename: attempting to rename file with null old name" );
 | 
						|
    AL_ASSERT( strlen( mName ) > 0, "UnRename: attempting to rename file with 0 length name" );
 | 
						|
    AL_ASSERT( strlen( mName.GetOldName() ) > 0, "UnRename: attempting to rename file with 0 length old name" );
 | 
						|
 | 
						|
    int status;
 | 
						|
 | 
						|
    if ( delete_on_clash ) {
 | 
						|
        status = unlink( mName.GetOldName() );
 | 
						|
        if ( status != 0 && errno != ENOENT )
 | 
						|
            return mStatus.SetError( AL_RENAME_ERROR,
 | 
						|
                                     "Error deleting %s before renaming %s.  "
 | 
						|
                                     "errno = %d",
 | 
						|
                                     mName.GetOldName(),
 | 
						|
                                     mName.GetName(),
 | 
						|
                                     errno );
 | 
						|
    }
 | 
						|
    status = rename( mName, mName.GetOldName() );
 | 
						|
    if ( status != 0 && errno != ENOENT )
 | 
						|
        return mStatus.SetError( AL_RENAME_ERROR,
 | 
						|
                                 "Error renaming %s to %s.  errno = %d",
 | 
						|
                                 mName.GetName(),
 | 
						|
                                 mName.GetOldName(),
 | 
						|
                                 errno );
 | 
						|
    ALStorage::mName = mName.GetOldName();
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Delete()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Delete the underlying physical file associated with an ALFile object.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::Delete()
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageDelete().
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageDelete().
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None, use ALStorageDelete().
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This function is called to delete the physical object associated with
 | 
						|
//  a file.  This simply means calling the unlink() function for the
 | 
						|
//  given name.
 | 
						|
//
 | 
						|
//  Since this is a virtual function in a derived class, C/VB/Delphi
 | 
						|
//  programmers aren't going to be able to call it directly.  They
 | 
						|
//  will instead call ALStorageDelete(), which will wind up here
 | 
						|
//  via the virtual function mechanism.
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  AL_DELETE_ERROR or AL_SUCCESS.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
//  ALFile::ALFile(), ALStorage::Delete()
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
 | 
						|
int AL_PROTO
 | 
						|
ALFile::Delete()  /* Tag public function */
 | 
						|
{
 | 
						|
    AL_ASSERT( miHandle == -1, "Delete: attempting to delete open file" );
 | 
						|
    AL_ASSERT( mName.GetName() != 0, "Delete: attempting to delete file with null name"  );
 | 
						|
    AL_ASSERT( strlen( mName ) > 0, "Delete: attempting to delete file with 0 length name" );
 | 
						|
 | 
						|
    int status = unlink( mName );
 | 
						|
    if ( status != 0 )
 | 
						|
        return mStatus.SetError( AL_DELETE_ERROR,
 | 
						|
                                 "Error deleting file %s, errno = %d ",
 | 
						|
                                 mName.GetName(),
 | 
						|
                                 errno );
 | 
						|
    return AL_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::Clone()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Clone this file object.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  ALStorage * ALFile::Clone( const char *name,
 | 
						|
//                             int object_type ) const;
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, this is an internal C++ function
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  name         :  The desired name of the new object.  Usually this will
 | 
						|
//                  be a name found in an Archive directory.
 | 
						|
//
 | 
						|
//  object_type  :  The type of object we want to create.  Only
 | 
						|
//                  AL_STORAGE_DEFAULT and AL_FILE_OBJECT will cause this
 | 
						|
//                  function to succeed.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  The virtual Clone() function is used by archiving programs to act
 | 
						|
//  as a virtual constructor.  When preparing to create storage objects
 | 
						|
//  based on the contents of an Archive directory, the archiving code can
 | 
						|
//  call Clone() for all the storage objects in its toolkit until it finds
 | 
						|
//  one that responds to its object type.
 | 
						|
//
 | 
						|
//  For example, if an archive contained an AL_MEMORY object, and we were
 | 
						|
//  extracting, and an ALFile object was in the toolkit, it would call
 | 
						|
//  ALFile::Clone() from the toolkit object, with an object type of
 | 
						|
//  AL_MEMORY_OBJECT.  This Clone() function would fail.  Hopefully, there
 | 
						|
//  would be a memory based storage object in the toolkit that would
 | 
						|
//  respond properly to the Clone() call.
 | 
						|
//
 | 
						|
//  Another object in the same archive might have an AL_FILE_OBJECT type.
 | 
						|
//  When the archiving code called Clone() again with that object type,
 | 
						|
//  we would successfully create the new File object in Clone().
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  Either a pointer to a newly constructed ALFile object, or a zero
 | 
						|
//  in case of error.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
ALStorage AL_DLL_FAR * AL_PROTO
 | 
						|
ALFile::Clone( const char AL_DLL_FAR *name,  /* Tag public function */
 | 
						|
               int object_type ) const
 | 
						|
{
 | 
						|
    switch ( object_type ) {
 | 
						|
        case AL_STORAGE_DEFAULT :
 | 
						|
        case AL_FILE_OBJECT :
 | 
						|
            return new ALFile( name );
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// NAME
 | 
						|
//
 | 
						|
//  ALFile::MakeDirectory()
 | 
						|
//
 | 
						|
// PLATFORMS/ENVIRONMENTS
 | 
						|
//
 | 
						|
//  Console  Windows  PM
 | 
						|
//  C++
 | 
						|
//
 | 
						|
// SHORT DESCRIPTION
 | 
						|
//
 | 
						|
//  Make a directory or a series of directories.
 | 
						|
//
 | 
						|
// C++ SYNOPSIS
 | 
						|
//
 | 
						|
//  #include "arclib.h"
 | 
						|
//  #include "filestor.h"
 | 
						|
//
 | 
						|
//  int ALFile::MakeDirectory()
 | 
						|
//
 | 
						|
// C SYNOPSIS
 | 
						|
//
 | 
						|
//  None, this is an internal C++ function
 | 
						|
//
 | 
						|
// VB SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DELPHI SYNOPSIS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// ARGUMENTS
 | 
						|
//
 | 
						|
//  None.
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  If ALFile::Create() fails due to the target directory
 | 
						|
//  not existing, it calls this routine.  This guy works his
 | 
						|
//  way through a long file name, trying to make directories
 | 
						|
//  all the way down, until it finishes or fails.
 | 
						|
//
 | 
						|
//  For example, if the mName member of this contains a string
 | 
						|
//  like c:\mark\al200\temp\temp.c, this routine will attempt
 | 
						|
//  to make, in turn:
 | 
						|
//                      c:\       (starts at root)
 | 
						|
//                      c:\mark
 | 
						|
//                      c:\mark\al200
 | 
						|
//                      c:\mark\al200\temp
 | 
						|
//
 | 
						|
// RETURNS
 | 
						|
//
 | 
						|
//  1 for success, 0 for failure.
 | 
						|
//
 | 
						|
// EXAMPLE
 | 
						|
//
 | 
						|
// SEE ALSO
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//   February 14, 1996  2.0A : New Release
 | 
						|
//
 | 
						|
 | 
						|
int AL_PROTO ALFile::MakeDirectory()  /* Tag protected function */
 | 
						|
{
 | 
						|
    char *p = new char[ strlen( mName ) + 1 ];
 | 
						|
    if ( p ) {
 | 
						|
        strcpy( p, mName );
 | 
						|
//
 | 
						|
//   Now I need to work through the entire file name, creating
 | 
						|
//   each directory in order.  I do this by stuffing a 0 into
 | 
						|
//   successive locations in the string where i find a '/' character,
 | 
						|
//   and calling mkdir() at each point.
 | 
						|
//
 | 
						|
        for ( size_t i = 0 ; p[ i ] ; i++ ) {
 | 
						|
            size_t j = i;
 | 
						|
            i = strcspn( p + i, "/\\" );
 | 
						|
            if ( i == strlen( p + j ) ) {
 | 
						|
                delete[] p;
 | 
						|
                return 1;
 | 
						|
            }
 | 
						|
            i += j;
 | 
						|
            char temp = p[ i ];
 | 
						|
            p[ i ] = '\0';
 | 
						|
            if ( mkdir( p ) == -1 && errno != EACCES ) {
 | 
						|
                delete[] p;
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
            p[ i ] = temp;
 | 
						|
        }
 | 
						|
        delete[] p;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 |