// // 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 #include #include #include #include #include #include #if defined( AL_OS2 ) #define INCL_DOSFILEMGR #include #include #if defined( AL_BORLAND ) #include #else #include #endif #else #include #include #include #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; }