//------------------------------------------------------------------------------
// Desc:	This file contains the F_DbSystem::dbRemove method.
//
// Tabs:	3
//
//		Copyright (c) 2001-2006 Novell, Inc. All Rights Reserved.
//
//		This program is free software; you can redistribute it and/or
//		modify it under the terms of version 2 of the GNU General Public
//		License as published by the Free Software Foundation.
//
//		This program is distributed in the hope that it will be useful,
//		but WITHOUT ANY WARRANTY; without even the implied warranty of
//		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//		GNU General Public License for more details.
//
//		You should have received a copy of the GNU General Public License
//		along with this program; if not, contact Novell, Inc.
//
//		To contact Novell about this file by physical or electronic mail,
//		you may find current contact information at www.novell.com
//
// $Id: fdbremov.cpp 3112 2006-01-19 13:12:40 -0700 (Thu, 19 Jan 2006) dsanders $
//------------------------------------------------------------------------------

#include "flaimsys.h"

/****************************************************************************
Desc:		Deletes all files of a database
****************************************************************************/
RCODE F_DbSystem::dbRemove(
	const char *		pszDbName,
		// [IN] Name of source database to be deleted.
	const char *		pszDataDir,
		// [IN] Directory where data files are located.
	const char *		pszRflDir,
		// [IN] RFL directory of database. NULL can be
		// passed to indicate that the log files are located
		// in the same directory as the other database files.
	FLMBOOL				bRemoveRflFiles)
{
	RCODE					rc = NE_XFLM_OK;
	FLMUINT				uiFileNumber;
	char *				pszTmpName = NULL;
	char *				pszRflDirName;
	char *				pszDataName;
	char *				pszBaseName;
	char *				pszExt;
	char *				pszDataExt;
	IF_DirHdl *			pDirHdl = NULL;

	// Cannot handle empty database name.

	if( !pszDbName || !(*pszDbName))
	{
		rc = RC_SET( NE_FLM_IO_INVALID_FILENAME);
		goto Exit;
	}

	// Allocate memory, so as to not consume stack.

	if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE * 3 + F_FILENAME_SIZE,
		&pszTmpName)))
	{
		goto Exit;
	}

	pszRflDirName = pszTmpName + F_PATH_MAX_SIZE;
	pszDataName = pszRflDirName + F_PATH_MAX_SIZE;
	pszBaseName = pszDataName + F_PATH_MAX_SIZE;

	// First make sure we have closed this database and gotten rid of
	// it from our internal memory tables - in case it had been open.

	if (RC_BAD( rc = checkDatabaseClosed( pszDbName, pszDataDir)))
	{
		goto Exit;
	}

	// Close all unused file handles
	
	if( gv_XFlmSysData.pFileHdlCache)
	{
		gv_XFlmSysData.pFileHdlCache->closeUnusedFiles();
	}
	
	if (pszDataDir && *pszDataDir)
	{
		if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathReduce( 
			pszDbName, pszDataName, pszBaseName)))
		{
			goto Exit;
		}
		f_strcpy( pszDataName, pszDataDir);
		if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathAppend( 
			pszDataName, pszBaseName)))
		{
			goto Exit;
		}
	}
	else
	{
		f_strcpy( pszDataName, pszDbName);
	}
	f_strcpy( pszTmpName, pszDbName);

	// Start deleting files, beginning with the main DB file.

	if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->deleteFile( pszDbName)))
	{
		if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
		{
			rc = NE_XFLM_OK;
		}
		else
		{
			goto Exit;
		}
	}

	// Find where the extension of the database name is

	pszExt = pszTmpName + f_strlen( pszTmpName) - 1;
	pszDataExt = pszDataName + f_strlen( pszDataName) - 1;
	while (pszExt != pszTmpName && *pszExt != '.')
	{
		pszExt--;

		// Both the db name and data name have the same
		// base name, so we can decrement pszDataExt
		// at the same time we decrement pszExt.

		pszDataExt--;
	}
	if (*pszExt != '.')
	{
		pszExt = pszTmpName + f_strlen( pszTmpName);
		pszDataExt = pszDataName + f_strlen( pszDataName);
	}

	// Delete the .lck file, if any

	f_strcpy( pszExt, ".lck");
	if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->deleteFile( pszTmpName)))
	{
		if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
		{
			rc = NE_XFLM_OK;
		}
		else
		{
			goto Exit;
		}
	}

	// Delete block (data) files.

	uiFileNumber = 1;
	for (;;)
	{
		F_SuperFileClient::bldSuperFileExtension( uiFileNumber, pszDataExt);

		if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->deleteFile( pszDataName)))
		{
			if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
			{
				rc = NE_XFLM_OK;
				break;
			}
			else
			{
				goto Exit;
			}
		}
		if (uiFileNumber == MAX_DATA_BLOCK_FILE_NUMBER)
		{
			break;
		}
		uiFileNumber++;
	}

	// Delete rollback log files.

	uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER;
	for (;;)
	{
		F_SuperFileClient::bldSuperFileExtension( uiFileNumber, pszExt);

		if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->deleteFile( pszTmpName)))
		{
			if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
			{
				rc = NE_XFLM_OK;
				break;
			}
			else
			{
				goto Exit;
			}
		}
		if (uiFileNumber == MAX_LOG_BLOCK_FILE_NUMBER)
		{
			break;
		}
		uiFileNumber++;
	}

	if (bRemoveRflFiles)
	{

		// Delete roll-forward log files.

		FLMBOOL	bCanDeleteDir;

		// Scan the RFL directory for RFL files.

		if (RC_BAD( rc = rflGetDirAndPrefix( pszDbName, pszRflDir, pszRflDirName)))
		{
			goto Exit;
		}

		// See if the directory exists.  If not, we are done.

		if (!gv_XFlmSysData.pFileSystem->isDir( pszRflDirName))
		{
			goto Exit;	// Should return NE_XFLM_OK
		}

		// Open the directory and scan for RFL files.
		// NOTE: DO NOT just call removeDir.  There may be other
		// things in the directory that we do not want to delete.
		// Look specifically for files that match our expected
		// name format for RFL files.

		if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->openDir( pszRflDirName,
										"*", &pDirHdl)))
		{
			goto Exit;
		}

		// Assume that we can delete the directory.  This will only
		// be set to FALSE if we can't delete all of the files in
		// the directory - i.e., some don't look like RFL log files.

		bCanDeleteDir = TRUE;
		for (;;)
		{
			if (RC_BAD( rc = pDirHdl->next()))
			{
				if (rc == NE_FLM_IO_NO_MORE_FILES)
				{
					rc = NE_XFLM_OK;
					break;
				}
				else
				{
					goto Exit;
				}
			}
			pDirHdl->currentItemPath( pszTmpName);
			if (pDirHdl->currentItemIsDir())
			{
				bCanDeleteDir = FALSE;
			}
			else if (!rflGetFileNum( pszTmpName, &uiFileNumber))
			{
				bCanDeleteDir = FALSE;
			}
			else
			{
				if( RC_BAD( rc =
							gv_XFlmSysData.pFileSystem->deleteFile( pszTmpName)))
				{
					if (rc == NE_FLM_IO_PATH_NOT_FOUND ||
						 rc == NE_FLM_IO_INVALID_FILENAME)
					{
						rc = NE_XFLM_OK;
					}
					else
					{
						goto Exit;
					}
				}
			}
		}

		// Attempt to delete the directory - if allowed.

		if (bCanDeleteDir)
		{

			// Need to release the directory handle so the
			// directory will be closed when we try to delete it
			// below.

			if (pDirHdl)
			{
				pDirHdl->Release();
				pDirHdl = NULL;
			}
			
			if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->removeDir( pszRflDirName)))
			{
				if (rc == NE_FLM_IO_PATH_NOT_FOUND || rc == NE_FLM_IO_INVALID_FILENAME)
				{
					rc = NE_XFLM_OK;
				}
				goto Exit;
			}
		}
	}

Exit:

	if( pszTmpName)
	{
		f_free( &pszTmpName);
	}

	if( pDirHdl)
	{
		pDirHdl->Release();
	}

	return( rc);
}
