git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@109 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1219 lines
26 KiB
C++
1219 lines
26 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: File system class.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1998-2003,2005-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: ffilesys.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
/****************************************************************************
|
|
Desc: Convert local time to UTC
|
|
Note: This code was basically copied from prtime.c
|
|
****************************************************************************/
|
|
FINLINE FLMUINT flmLocalToUTC(
|
|
FLMUINT uiSeconds)
|
|
{
|
|
return( uiSeconds + f_timeGetLocalOffset());
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Create a file, return a file handle to created file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::Create(
|
|
const char * pFilePath,
|
|
FLMUINT uiIoFlags,
|
|
F_FileHdl ** ppFileHdl)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_FileHdlImp * pFileHdl = NULL;
|
|
|
|
if (RC_BAD( rc = getFileHdl( &pFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = pFileHdl->Create( pFilePath, uiIoFlags)))
|
|
{
|
|
pFileHdl->Release();
|
|
pFileHdl = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
*ppFileHdl = (F_FileHdl *)pFileHdl;
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Create a block-oriented file, return a file handle to created file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::CreateBlockFile(
|
|
const char * pFilePath,
|
|
FLMUINT uiIoFlags,
|
|
FLMUINT uiBlockSize,
|
|
F_FileHdlImp ** ppFileHdl)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_FileHdlImp * pFileHdl = NULL;
|
|
|
|
if (RC_BAD( rc = getFileHdl( &pFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
#ifdef FLM_WIN
|
|
pFileHdl->SetBlockSize( uiBlockSize);
|
|
#else
|
|
F_UNREFERENCED_PARM( uiBlockSize);
|
|
#endif
|
|
|
|
if (RC_BAD( rc = pFileHdl->Create( pFilePath, uiIoFlags)))
|
|
{
|
|
pFileHdl->Release();
|
|
pFileHdl = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
*ppFileHdl = pFileHdl;
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Create a unique file, return a file handle to created file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::CreateUnique(
|
|
char * pszDirPath,
|
|
const char * pszFileExtension,
|
|
FLMUINT uiIoFlags,
|
|
F_FileHdl ** ppFileHdl)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_FileHdlImp * pFileHdl = NULL;
|
|
|
|
if( RC_BAD( rc = getFileHdl( &pFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pFileHdl->CreateUnique(
|
|
pszDirPath, pszFileExtension, uiIoFlags)))
|
|
{
|
|
pFileHdl->Release();
|
|
pFileHdl = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
*ppFileHdl = (F_FileHdl *)pFileHdl;
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Open a file, return a file handle to opened file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::Open(
|
|
const char * pFilePath,
|
|
FLMUINT uiIoFlags,
|
|
F_FileHdl ** ppFileHdl)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_FileHdlImp * pFileHdl = NULL;
|
|
|
|
if (RC_BAD( rc = getFileHdl( &pFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = pFileHdl->Open( pFilePath, uiIoFlags)))
|
|
{
|
|
pFileHdl->Release();
|
|
pFileHdl = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
*ppFileHdl = (F_FileHdl *)pFileHdl;
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Open a block-oriented file, return a file handle to opened file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::OpenBlockFile(
|
|
const char * pFilePath,
|
|
FLMUINT uiIoFlags,
|
|
FLMUINT uiBlockSize,
|
|
F_FileHdlImp ** ppFileHdl)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_FileHdlImp * pFileHdl = NULL;
|
|
|
|
if (RC_BAD( rc = getFileHdl( &pFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
#ifdef FLM_WIN
|
|
pFileHdl->SetBlockSize( uiBlockSize);
|
|
#else
|
|
F_UNREFERENCED_PARM( uiBlockSize);
|
|
#endif
|
|
|
|
if (RC_BAD( rc = pFileHdl->Open( pFilePath, uiIoFlags)))
|
|
{
|
|
pFileHdl->Release();
|
|
pFileHdl = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
*ppFileHdl = pFileHdl;
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Open a directory, return a file handle to opened directory.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::OpenDir(
|
|
const char * pszDirPath,
|
|
const char * pszPattern,
|
|
F_DirHdl ** ppDirHdl)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_DirHdl * pDirHdl = NULL;
|
|
|
|
if( (pDirHdl = f_new F_DirHdlImp) == NULL)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDirHdl->OpenDir( pszDirPath, pszPattern)))
|
|
{
|
|
pDirHdl->Release();
|
|
pDirHdl = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
*ppDirHdl = pDirHdl;
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Create a directory (and parent directories if necessary).
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::CreateDir(
|
|
const char * pszDirPath)
|
|
{
|
|
char * pszParentDir = NULL;
|
|
RCODE rc = FERR_OK;
|
|
|
|
if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE, &pszParentDir)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Discover the parent directory of the given one
|
|
|
|
if( RC_BAD( rc = f_pathReduce( pszDirPath, pszParentDir, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// If f_pathReduce couldn't reduce the path at all, then an invalid
|
|
// path was supplied.
|
|
|
|
if( f_strcmp( pszDirPath, pszParentDir) == 0)
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
// If a parent directory was found, and it doesn't already exist, create it
|
|
|
|
if( *pszParentDir)
|
|
{
|
|
// If the "parent" is actually a regular file we need to return an error
|
|
|
|
if( RC_OK( gv_FlmSysData.pFileSystem->Exists( pszParentDir)))
|
|
{
|
|
if( !gv_FlmSysData.pFileSystem->IsDir( pszParentDir))
|
|
{
|
|
rc = RC_SET( FERR_IO_ACCESS_DENIED);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Recurse on the parent directory
|
|
|
|
else if( RC_BAD( rc = CreateDir( pszParentDir)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
#if defined( FLM_WIN)
|
|
|
|
if( !CreateDirectory((LPTSTR)pszDirPath, NULL))
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_CREATING_FILE);
|
|
}
|
|
|
|
#elif defined( FLM_UNIX)
|
|
|
|
// Create a new directory with mode parameter 0777. From the linux
|
|
// man (2) mkdir page:
|
|
|
|
// mode specifies the permissions to use. It is modified by the
|
|
// process's umask in the usual way: the permissions of the created
|
|
// file are (mode & ~umask).
|
|
|
|
if( mkdir( pszDirPath, 0700) == -1 )
|
|
{
|
|
rc = MapErrnoToFlaimErr( errno, FERR_CREATING_FILE);
|
|
}
|
|
|
|
#elif defined( FLM_NLM)
|
|
|
|
rc = _CreateDir( pszDirPath);
|
|
|
|
#endif
|
|
|
|
Exit:
|
|
if (pszParentDir)
|
|
{
|
|
f_free( &pszParentDir);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: NetWare implementation to create a directory
|
|
Input:
|
|
pPathToDirectory = fully-qualified path to the directory to be created
|
|
Examples:
|
|
In this example, the directory 'myDir' would be created:
|
|
sys:\system\myDir
|
|
|
|
Note that ConvertPathString doesn't support server names. So
|
|
it returns an error on paths like:
|
|
server-name/volume:\directory_1
|
|
|
|
Return:
|
|
FERR_OK = success, otherwise there was an error
|
|
Note that the parent directory must exist. If it doesn't, an error will
|
|
occur.
|
|
****************************************************************************/
|
|
#ifdef FLM_NLM
|
|
RCODE F_FileSystemImp::_CreateDir(
|
|
const char * pPathToDirectory)
|
|
{
|
|
FLMBYTE pucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
FLMBYTE pucLNamePath[ F_PATH_MAX_SIZE];
|
|
LONG lVolumeID;
|
|
LONG lPathID;
|
|
LONG lLNamePathCount;
|
|
LONG lNewDirectoryID;
|
|
void *pNotUsed;
|
|
LONG lErrorCode;
|
|
RCODE rc = FERR_OK;
|
|
|
|
f_strcpy( (char *)&pucPseudoLNamePath[1], pPathToDirectory);
|
|
pucPseudoLNamePath[0] = (FLMBYTE)f_strlen( pPathToDirectory);
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, pucPseudoLNamePath, &lVolumeID,
|
|
&lPathID, pucLNamePath, &lLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (lErrorCode = CreateDirectory( 0, lVolumeID, lPathID, pucLNamePath,
|
|
lLNamePathCount, LONGNameSpace, MaximumDirectoryAccessBits,
|
|
&lNewDirectoryID, &pNotUsed)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( lErrorCode)
|
|
{
|
|
rc = MapNWtoFlaimError( lErrorCode, FERR_CREATING_FILE);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Remove a directory.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::RemoveDir(
|
|
const char * pszDirPath,
|
|
FLMBOOL bClear)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_DirHdl * pDirHdl = NULL;
|
|
char szFilePath[ F_PATH_MAX_SIZE];
|
|
|
|
if( bClear)
|
|
{
|
|
if( RC_BAD( rc = OpenDir( pszDirPath, "*", &pDirHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Delete everything in the directory
|
|
|
|
for( rc = pDirHdl->Next(); RC_OK( rc) ; rc = pDirHdl->Next())
|
|
{
|
|
pDirHdl->CurrentItemPath( szFilePath);
|
|
if( !pDirHdl->CurrentItemIsDir())
|
|
{
|
|
if( RC_BAD( rc = Delete( szFilePath)))
|
|
{
|
|
if( rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = RemoveDir( szFilePath, bClear)))
|
|
{
|
|
if( rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Need to release the directory handle so the
|
|
// directory will be closed when we try to delete it
|
|
// below.
|
|
|
|
pDirHdl->Release();
|
|
pDirHdl = NULL;
|
|
}
|
|
|
|
if( RC_BAD( rc = RemoveEmptyDir( pszDirPath)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDirHdl)
|
|
{
|
|
pDirHdl->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Remove an empty directory
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::RemoveEmptyDir(
|
|
const char * pszDirPath)
|
|
{
|
|
#if defined( FLM_WIN)
|
|
|
|
if( !RemoveDirectory( (LPTSTR)pszDirPath))
|
|
{
|
|
return( MapWinErrorToFlaim( GetLastError(), FERR_DELETING_FILE));
|
|
}
|
|
|
|
return( FERR_OK);
|
|
|
|
#elif defined( FLM_UNIX)
|
|
|
|
if( rmdir( pszDirPath) == -1 )
|
|
{
|
|
return( MapErrnoToFlaimErr( errno, FERR_DELETING_FILE));
|
|
}
|
|
|
|
return( FERR_OK);
|
|
|
|
#elif defined( FLM_NLM)
|
|
RCODE rc = FERR_OK;
|
|
FLMBYTE pucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
FLMBYTE pucLNamePath[ F_PATH_MAX_SIZE];
|
|
LONG lVolumeID;
|
|
LONG lPathID;
|
|
LONG lLNamePathCount;
|
|
LONG lErrorCode;
|
|
|
|
f_strcpy( (char *)&pucPseudoLNamePath[1], pszDirPath);
|
|
pucPseudoLNamePath[0] = (FLMBYTE)f_strlen( pszDirPath);
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, pucPseudoLNamePath, &lVolumeID,
|
|
&lPathID, pucLNamePath, &lLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (lErrorCode = DeleteDirectory( 0, lVolumeID, lPathID, pucLNamePath,
|
|
lLNamePathCount, LONGNameSpace)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( lErrorCode)
|
|
{
|
|
rc = MapNWtoFlaimError( lErrorCode, FERR_DELETING_FILE);
|
|
}
|
|
|
|
return( rc);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Determine if a file or directory exists.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::Exists(
|
|
const char * pPath)
|
|
{
|
|
#if defined( FLM_NLM)
|
|
return( NWTestIfFileExists( pPath));
|
|
#elif defined( FLM_WIN)
|
|
DWORD dwFileAttr = GetFileAttributes( (LPTSTR)pPath);
|
|
|
|
if( dwFileAttr == (DWORD)-1)
|
|
{
|
|
return( RC_SET( FERR_IO_PATH_NOT_FOUND));
|
|
}
|
|
|
|
return( FERR_OK);
|
|
|
|
#else
|
|
|
|
// Check for the file's existence
|
|
|
|
if( access( pPath, F_OK) == -1)
|
|
{
|
|
return( MapErrnoToFlaimErr( errno, FERR_CHECKING_FILE_EXISTENCE));
|
|
}
|
|
|
|
return( FERR_OK);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Get the time stamp of the last modification to this file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::GetTimeStamp(
|
|
const char * pPath,
|
|
FLMUINT * puiTimeStamp)
|
|
{
|
|
#if defined( FLM_NLM)
|
|
FLMUINT uiTmp;
|
|
FLMBYTE ucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
FLMBYTE ucLNamePath[ F_PATH_MAX_SIZE];
|
|
LONG lVolumeID;
|
|
LONG lPathID;
|
|
LONG lLNamePathCount;
|
|
LONG lDirectoryID;
|
|
LONG lErrorCode;
|
|
struct DirectoryStructure *
|
|
pFileInfo = NULL;
|
|
RCODE rc = FERR_OK;
|
|
|
|
flmAssert( puiTimeStamp );
|
|
*puiTimeStamp = 0;
|
|
|
|
f_strcpy( (char *)&ucPseudoLNamePath[1], pPath);
|
|
ucPseudoLNamePath[ 0] = (FLMBYTE)f_strlen( pPath );
|
|
|
|
if( (lErrorCode = ConvertPathString( 0, 0, ucPseudoLNamePath, &lVolumeID,
|
|
&lPathID, ucLNamePath, &lLNamePathCount)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (lErrorCode = GetEntryFromPathStringBase( 0, lVolumeID, 0, ucLNamePath,
|
|
lLNamePathCount, LONGNameSpace, LONGNameSpace, &pFileInfo,
|
|
&lDirectoryID)) != 0)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pFileInfo)
|
|
{
|
|
FLMUINT uiTime;
|
|
FLMUINT uiDate;
|
|
F_TMSTAMP dateTime;
|
|
LONG DayMask = 0x001F;
|
|
LONG MonthMask = 0x01E0;
|
|
LONG YearMask = 0xFE00;
|
|
LONG SecMask = 0x001F;
|
|
LONG MinMask = 0x07E0;
|
|
LONG HourMask = 0xF800;
|
|
|
|
//Get the low-order 16 bits
|
|
|
|
uiTime = (FLMUINT)pFileInfo->DLastUpdatedDateAndTime;
|
|
|
|
//Get the high-order 16 bits
|
|
|
|
uiDate = (FLMUINT)(pFileInfo->DLastUpdatedDateAndTime >> 16);
|
|
|
|
f_memset( &dateTime, 0, sizeof( dateTime));
|
|
dateTime.second = (FLMBYTE) ((uiTime & SecMask) * 2);
|
|
dateTime.minute = (FLMBYTE) ((uiTime & MinMask) >> 5);
|
|
dateTime.hour = (FLMBYTE) ((uiTime & HourMask) >> 11);
|
|
dateTime.day = (FLMBYTE) (uiDate & DayMask);
|
|
dateTime.month = (FLMBYTE) ((uiDate & MonthMask) >> 5)-1;
|
|
dateTime.year = (FLMUINT16)(((uiDate & YearMask) >> 9) + 1980);
|
|
|
|
f_timeDateToSeconds( &dateTime, &uiTmp);
|
|
*puiTimeStamp = uiTmp;
|
|
*puiTimeStamp = flmLocalToUTC(*puiTimeStamp);
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( lErrorCode != 0 )
|
|
{
|
|
rc = MapNWtoFlaimError(lErrorCode, FERR_PARSING_FILE_NAME);
|
|
}
|
|
|
|
return( rc);
|
|
|
|
#elif defined( FLM_WIN)
|
|
|
|
RCODE rc = FERR_OK;
|
|
WIN32_FIND_DATA find_data;
|
|
FILETIME ftLocalFileTime;
|
|
SYSTEMTIME stLastFileWriteTime;
|
|
HANDLE hSearch = INVALID_HANDLE_VALUE;
|
|
F_TMSTAMP tmstamp;
|
|
|
|
hSearch = FindFirstFile( (LPTSTR)pPath, &find_data);
|
|
if( hSearch == INVALID_HANDLE_VALUE)
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_OPENING_FILE);
|
|
|
|
switch( rc)
|
|
{
|
|
case FERR_IO_NO_MORE_FILES:
|
|
rc = RC_SET( FERR_IO_PATH_NOT_FOUND);
|
|
goto Exit;
|
|
default:
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( FileTimeToLocalFileTime( &(find_data.ftLastWriteTime),
|
|
&ftLocalFileTime) == FALSE)
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_OPENING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
if( FileTimeToSystemTime( &ftLocalFileTime, &stLastFileWriteTime) == FALSE)
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(), FERR_OPENING_FILE);
|
|
goto Exit;
|
|
}
|
|
|
|
f_memset( &tmstamp, 0, sizeof( F_TMSTAMP));
|
|
|
|
tmstamp.hour = (FLMBYTE)stLastFileWriteTime.wHour;
|
|
tmstamp.minute = (FLMBYTE)stLastFileWriteTime.wMinute;
|
|
tmstamp.second = (FLMBYTE)stLastFileWriteTime.wSecond;
|
|
tmstamp.hundredth = (FLMBYTE)stLastFileWriteTime.wMilliseconds;
|
|
tmstamp.year = (FLMUINT16)stLastFileWriteTime.wYear;
|
|
tmstamp.month = (FLMBYTE)(stLastFileWriteTime.wMonth - 1);
|
|
tmstamp.day = (FLMBYTE)stLastFileWriteTime.wDay;
|
|
|
|
f_timeDateToSeconds( &tmstamp, puiTimeStamp);
|
|
|
|
Exit:
|
|
|
|
if( hSearch != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose( hSearch);
|
|
}
|
|
|
|
if( RC_OK( rc))
|
|
{
|
|
*puiTimeStamp = flmLocalToUTC( *puiTimeStamp);
|
|
}
|
|
|
|
return( rc);
|
|
|
|
#else
|
|
|
|
struct stat filestatus;
|
|
|
|
if( stat( pPath, &filestatus) == -1)
|
|
{
|
|
return( MapErrnoToFlaimErr( errno, FERR_GETTING_FILE_INFO));
|
|
}
|
|
|
|
*puiTimeStamp = (FLMUINT)filestatus.st_mtime;
|
|
return( FERR_OK);
|
|
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Determine if a path is a directory.
|
|
****************************************************************************/
|
|
FLMBOOL F_FileSystemImp::IsDir(
|
|
const char * pPath)
|
|
{
|
|
FLMBOOL bIsDir = FALSE;
|
|
|
|
#if defined( FLM_NLM)
|
|
LONG lIsFile;
|
|
FLMBYTE ucPseudoLNamePath[ F_PATH_MAX_SIZE + 1];
|
|
FLMBYTE ucLNamePath[ F_PATH_MAX_SIZE];
|
|
LONG lVolumeID;
|
|
LONG lPathID;
|
|
LONG lLNamePathCount;
|
|
LONG lDirectoryID;
|
|
|
|
f_strcpy( (char *)&ucPseudoLNamePath[1], pPath);
|
|
ucPseudoLNamePath[0] = (FLMBYTE)f_strlen( pPath );
|
|
if( ConvertPathString( 0, 0, ucPseudoLNamePath, &lVolumeID, &lPathID,
|
|
ucLNamePath, &lLNamePathCount) == 0)
|
|
{
|
|
if( MapPathToDirectoryNumber( 0, lVolumeID, 0, ucLNamePath,
|
|
lLNamePathCount, LONGNameSpace, &lDirectoryID, &lIsFile) == 0)
|
|
{
|
|
bIsDir = (FLMBOOL)((lIsFile == 0) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE);
|
|
}
|
|
}
|
|
|
|
return( bIsDir);
|
|
|
|
#elif defined( FLM_WIN)
|
|
|
|
DWORD FileAttr = GetFileAttributes( (LPTSTR)pPath);
|
|
|
|
if( FileAttr == 0xFFFFFFFF)
|
|
{
|
|
return( bIsDir);
|
|
}
|
|
|
|
return( FileAttr & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;
|
|
|
|
#else
|
|
|
|
struct stat filestatus;
|
|
|
|
if( stat( pPath, &filestatus) == -1)
|
|
{
|
|
return bIsDir;
|
|
}
|
|
|
|
return( S_ISDIR( filestatus.st_mode)) ? TRUE : FALSE;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Delete a file or directory
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::Delete(
|
|
const char * pPath)
|
|
{
|
|
#if defined( FLM_NLM)
|
|
|
|
return( NWDeleteFile( pPath));
|
|
|
|
#elif defined( FLM_WIN)
|
|
|
|
if( DeleteFile( (LPTSTR)pPath) == FALSE)
|
|
{
|
|
return( MapWinErrorToFlaim( GetLastError(), FERR_DELETING_FILE));
|
|
}
|
|
|
|
return FERR_OK;
|
|
|
|
#else
|
|
|
|
struct stat FileStat;
|
|
|
|
if( stat( pPath, &FileStat) == -1)
|
|
{
|
|
return( MapErrnoToFlaimErr( errno, FERR_GETTING_FILE_INFO));
|
|
}
|
|
|
|
if( S_ISDIR(FileStat.st_mode))
|
|
{
|
|
return( RC_SET( FERR_IO_ACCESS_DENIED));
|
|
}
|
|
|
|
if( unlink( pPath) == -1)
|
|
{
|
|
return( MapErrnoToFlaimErr( errno, FERR_DELETING_FILE));
|
|
}
|
|
|
|
return( FERR_OK);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Copy a file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::Copy(
|
|
const char * pSrcFilePath,
|
|
const char * pDestFilePath,
|
|
FLMBOOL bOverwrite,
|
|
FLMUINT * puiBytesCopied)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
F_FileHdl * pSrcFileHdl = NULL;
|
|
F_FileHdl * pDestFileHdl = NULL;
|
|
FLMBOOL bCreatedDest = FALSE;
|
|
FLMUINT uiSrcSize;
|
|
|
|
// See if the destination file exists. If it does, see if it is
|
|
// OK to overwrite it. If so, delete it.
|
|
|
|
if( Exists( pDestFilePath) == FERR_OK)
|
|
{
|
|
if( !bOverwrite)
|
|
{
|
|
rc = RC_SET( FERR_IO_ACCESS_DENIED);
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = Delete( pDestFilePath)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Open the source file
|
|
|
|
if( RC_BAD( rc = Open( pSrcFilePath, F_IO_RDONLY | F_IO_SH_DENYNONE,
|
|
&pSrcFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pSrcFileHdl->Size( &uiSrcSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Create the destination file
|
|
|
|
if( RC_BAD( rc = Create( pDestFilePath, F_IO_RDWR | F_IO_SH_DENYNONE,
|
|
&pDestFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bCreatedDest = TRUE;
|
|
|
|
// Do the copy
|
|
|
|
if( RC_BAD( rc = flmCopyPartial( pSrcFileHdl, 0, uiSrcSize,
|
|
pDestFileHdl, 0, puiBytesCopied)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pSrcFileHdl)
|
|
{
|
|
pSrcFileHdl->Close();
|
|
pSrcFileHdl->Release();
|
|
}
|
|
|
|
if( pDestFileHdl)
|
|
{
|
|
pDestFileHdl->Close();
|
|
pDestFileHdl->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bCreatedDest)
|
|
{
|
|
(void)Delete( pDestFilePath);
|
|
}
|
|
|
|
*puiBytesCopied = 0;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Rename a file.
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::Rename(
|
|
const char * pFilePath,
|
|
const char * pNewFilePath)
|
|
{
|
|
#if defined( FLM_NLM)
|
|
|
|
return( NWRenameFile( pFilePath, pNewFilePath));
|
|
|
|
#elif defined( FLM_WIN)
|
|
DWORD error;
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiBytesCopied;
|
|
|
|
// Try to move the file by doing a rename first, otherwise copy the file
|
|
|
|
if( (MoveFile( (LPTSTR)pFilePath, (LPTSTR)pNewFilePath)) != TRUE)
|
|
{
|
|
error = GetLastError();
|
|
|
|
switch( error)
|
|
{
|
|
case ERROR_NOT_SAME_DEVICE:
|
|
case ERROR_NO_MORE_FILES:
|
|
case NO_ERROR:
|
|
{
|
|
if( Copy( pFilePath, pNewFilePath, TRUE, &uiBytesCopied))
|
|
{
|
|
rc = RC_SET( FERR_IO_COPY_ERR);
|
|
}
|
|
else
|
|
{
|
|
rc = F_FileSystemImp::Delete( pFilePath);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = MapWinErrorToFlaim( error, FERR_RENAMING_FILE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
|
|
#else
|
|
RCODE rc = FERR_OK;
|
|
FLMBOOL bSrcIsDir;
|
|
FLMUINT uiBytesCopied;
|
|
|
|
if( RC_BAD( rc = targetIsDir( (const char *)pFilePath, &bSrcIsDir)))
|
|
{
|
|
return( rc);
|
|
}
|
|
|
|
errno = 0;
|
|
|
|
if( RC_BAD( renameSafe( pFilePath, pNewFilePath)))
|
|
{
|
|
switch( errno)
|
|
{
|
|
case EXDEV:
|
|
{
|
|
if( bSrcIsDir)
|
|
{
|
|
return( RC_SET( FERR_IO_PATH_CREATE_FAILURE));
|
|
}
|
|
else
|
|
{
|
|
if( Copy( pFilePath, pNewFilePath, TRUE, &uiBytesCopied))
|
|
{
|
|
return( RC_SET( FERR_IO_COPY_ERR));
|
|
}
|
|
|
|
F_FileSystemImp::Delete( pFilePath);
|
|
return( FERR_OK);
|
|
}
|
|
}
|
|
|
|
default:
|
|
{
|
|
if( errno == ENOENT)
|
|
{
|
|
return( RC_SET( FERR_IO_RENAME_FAILURE));
|
|
}
|
|
else
|
|
{
|
|
return( MapErrnoToFlaimErr( errno, FERR_RENAMING_FILE));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FERR_OK);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Get the sector size (not supported on all platforms).
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::GetSectorSize(
|
|
const char * pFileName,
|
|
FLMUINT * puiSectorSize)
|
|
{
|
|
#ifdef FLM_NLM
|
|
|
|
F_UNREFERENCED_PARM( pFileName);
|
|
*puiSectorSize = 512;
|
|
return( FERR_OK);
|
|
|
|
#elif defined( FLM_WIN)
|
|
|
|
RCODE rc = FERR_OK;
|
|
DWORD udSectorsPerCluster;
|
|
DWORD udBytesPerSector;
|
|
DWORD udNumberOfFreeClusters;
|
|
DWORD udTotalNumberOfClusters;
|
|
char szVolume [256];
|
|
char * pszVolume;
|
|
FLMUINT uiLen;
|
|
|
|
if( !pFileName)
|
|
{
|
|
pszVolume = NULL;
|
|
}
|
|
else
|
|
{
|
|
f_pathParse( pFileName, NULL, szVolume, NULL, NULL);
|
|
|
|
if( !szVolume [0])
|
|
{
|
|
pszVolume = NULL;
|
|
}
|
|
else
|
|
{
|
|
uiLen = f_strlen( szVolume);
|
|
|
|
if( szVolume [uiLen - 1] == ':')
|
|
{
|
|
szVolume [uiLen] = '\\';
|
|
szVolume [uiLen + 1] = 0;
|
|
}
|
|
pszVolume = &szVolume [0];
|
|
}
|
|
}
|
|
|
|
if( !GetDiskFreeSpace( (LPCTSTR)pszVolume, &udSectorsPerCluster,
|
|
&udBytesPerSector, &udNumberOfFreeClusters,
|
|
&udTotalNumberOfClusters))
|
|
{
|
|
rc = MapWinErrorToFlaim( GetLastError(),
|
|
FERR_INITIALIZING_IO_SYSTEM);
|
|
*puiSectorSize = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
*puiSectorSize = (FLMUINT)udBytesPerSector;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
|
|
#else
|
|
|
|
F_UNREFERENCED_PARM( pFileName);
|
|
*puiSectorSize = 0;
|
|
return( FERR_OK);
|
|
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Set the Read-Only Attribute (not supported on all platforms).
|
|
****************************************************************************/
|
|
RCODE F_FileSystemImp::SetReadOnly(
|
|
const char * pszFileName,
|
|
FLMBOOL bReadOnly)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
#if defined( FLM_UNIX)
|
|
struct stat filestatus;
|
|
|
|
if( stat( (char *)pszFileName, &filestatus))
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( bReadOnly)
|
|
{
|
|
filestatus.st_mode &= ~S_IWUSR;
|
|
}
|
|
else
|
|
{
|
|
filestatus.st_mode |= S_IWUSR;
|
|
}
|
|
|
|
if ( chmod( (char *)pszFileName, filestatus.st_mode))
|
|
{
|
|
rc = RC_SET( FERR_FAILURE);
|
|
goto Exit;
|
|
}
|
|
|
|
#elif defined( FLM_WIN)
|
|
|
|
DWORD dwAttr;
|
|
|
|
dwAttr = GetFileAttributes( (LPTSTR)pszFileName);
|
|
if( dwAttr == (DWORD)-1)
|
|
{
|
|
rc = RC_SET( FERR_IO_PATH_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
if ( bReadOnly)
|
|
{
|
|
dwAttr |= F_IO_FA_RDONLY;
|
|
}
|
|
else
|
|
{
|
|
dwAttr &= ~F_IO_FA_RDONLY;
|
|
}
|
|
|
|
if( !SetFileAttributes( (LPTSTR)pszFileName, dwAttr))
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_FAILURE);
|
|
goto Exit;
|
|
}
|
|
#else
|
|
F_UNREFERENCED_PARM( pszFileName);
|
|
F_UNREFERENCED_PARM( bReadOnly);
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_NOT_IMPLEMENTED);
|
|
goto Exit;
|
|
#endif
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: stat tpath to see if it is a directory
|
|
****************************************************************************/
|
|
#if defined( FLM_UNIX)
|
|
RCODE F_FileSystemImp::targetIsDir(
|
|
const char * pszPath,
|
|
FLMBOOL * pbIsDir)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
struct stat sbuf;
|
|
|
|
*pbIsDir = FALSE;
|
|
|
|
if( stat( pszPath, &sbuf) < 0)
|
|
{
|
|
rc = MapErrnoToFlaimErr( errno, FERR_IO_ACCESS_DENIED);
|
|
}
|
|
else if( (sbuf.st_mode & S_IFMT) == S_IFDIR)
|
|
{
|
|
*pbIsDir = TRUE;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: Rename an existing file (typically an "X" locked file to an
|
|
unlocked file) using a safe (non-race) method. To ensure that
|
|
an existing file is not being overwritten by a rename operation,
|
|
we will first create a new file with the desired name (using the
|
|
CREAT and EXCL options, (ensuring a unique file name)). Then,
|
|
the source file will be renamed to new name.
|
|
****************************************************************************/
|
|
#if defined( FLM_UNIX)
|
|
RCODE F_FileSystemImp::renameSafe(
|
|
const char * pszSrcFile,
|
|
const char * pszDestFile)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
struct stat temp_stat_buf;
|
|
|
|
// There appears to be a bug in newer versions of glibc (it was first
|
|
// noticed in RedHat 8) where the behavior of the reaname() function has
|
|
// changed. According to the man page, rename should allow you to
|
|
// overwrite an existing directory (ie: rename( "OldDir", "NewDir")
|
|
// should succeed, even if NewDir already exists). In order to
|
|
// avoid having #ifdefs for individual Linux distributions, we
|
|
// decided not to rely on this behavior, and simply do the
|
|
// existence test ourselves. Thus, the race condition that this
|
|
// function was supposed to avoid is theoretically possible, but as long
|
|
// as this function only gets called while the database is closed, it won't
|
|
// be a problem.
|
|
|
|
errno = 0;
|
|
if( stat( pszDestFile, &temp_stat_buf) != -1)
|
|
{
|
|
// If we were able to stat it, then the file obviously exists...
|
|
|
|
rc = RC_SET( FERR_IO_RENAME_FAILURE);
|
|
goto Exit;
|
|
}
|
|
else
|
|
{
|
|
if( errno != ENOENT)
|
|
{
|
|
// ENOENT means the file didn't exist, which is what we were
|
|
// hoping for
|
|
|
|
rc = MapErrnoToFlaimErr( errno, FERR_IO_RENAME_FAILURE);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
errno = 0;
|
|
if( rename( pszSrcFile, pszDestFile) != 0)
|
|
{
|
|
rc = MapErrnoToFlaimErr( errno, FERR_IO_RENAME_FAILURE);
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
#endif
|