//------------------------------------------------------------------------------ // Desc: Class for doing file directory operations. // Tabs: 3 // // Copyright (c) 1998-2007 Novell, Inc. All Rights Reserved. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; version 2.1 // of the License. // // This library 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 // Library Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; 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$ //------------------------------------------------------------------------------ #include "ftksys.h" #define ERR_NO_FILES_FOUND 0xFF #define ERR_INVALID_PATH 0x9C #if defined( FLM_WIN) #define F_IO_FA_NORMAL FILE_ATTRIBUTE_NORMAL // Normal file #define F_IO_FA_RDONLY FILE_ATTRIBUTE_READONLY // Read only attribute #define F_IO_FA_HIDDEN FILE_ATTRIBUTE_HIDDEN // Hidden file #define F_IO_FA_SYSTEM FILE_ATTRIBUTE_SYSTEM // System file #define F_IO_FA_VOLUME FILE_ATTRIBUTE_VOLUME // Volume label #define F_IO_FA_DIRECTORY FILE_ATTRIBUTE_DIRECTORY // Directory #define F_IO_FA_ARCHIVE FILE_ATTRIBUTE_ARCHIVE // Archive FSTATIC FLMBOOL f_fileMeetsFindCriteria( F_IO_FIND_DATA * pFindData); #elif defined( FLM_UNIX) || defined( FLM_LIBC_NLM) #define F_IO_FA_NORMAL 0x01 // Normal file, no attributes #define F_IO_FA_RDONLY 0x02 // Read only attribute #define F_IO_FA_HIDDEN 0x04 // Hidden file #define F_IO_FA_SYSTEM 0x08 // System file #define F_IO_FA_VOLUME 0x10 // Volume label #define F_IO_FA_DIRECTORY 0x20 // Directory #define F_IO_FA_ARCHIVE 0x40 // Archive FSTATIC int Find1( char * FindTemplate, F_IO_FIND_DATA * DirInfo); FSTATIC int Find2( F_IO_FIND_DATA * DirStuff); FSTATIC FLMBYTE ReturnAttributes( mode_t FileMode, char * pszFileName); FSTATIC int RetrieveFileStat( char * FilePath, struct stat * StatusRec); #elif !defined( FLM_RING_ZERO_NLM) #error Platform not supported #endif RCODE f_fileFindFirst( char * pszSearchPath, FLMUINT uiSearchAttrib, F_IO_FIND_DATA * find_data, char * pszFoundPath, FLMUINT * puiFoundAttrib); RCODE f_fileFindNext( F_IO_FIND_DATA * pFindData, char * pszFoundPath, FLMUINT * puiFoundAttrib); void f_fileFindClose( F_IO_FIND_DATA * pFindData); /**************************************************************************** Desc: ****************************************************************************/ RCODE f_allocDirHdl( F_DirHdl ** ppDirHdl) { if( (*ppDirHdl = f_new F_DirHdl) == NULL) { return( RC_SET( NE_FLM_MEM)); } return( NE_FLM_OK); } /**************************************************************************** Desc: ****************************************************************************/ F_DirHdl::F_DirHdl() { m_rc = NE_FLM_OK; m_bFirstTime = TRUE; m_bFindOpen = FALSE; m_uiAttrib = 0; m_szPattern[ 0] = '\0'; } /**************************************************************************** Desc: ****************************************************************************/ F_DirHdl::~F_DirHdl() { #ifndef FLM_RING_ZERO_NLM if( m_bFindOpen) { f_fileFindClose( &m_FindData); } #endif } /**************************************************************************** Desc: ****************************************************************************/ const char * FTKAPI F_DirHdl::currentItemName( void) { const char * pszName = NULL; #ifndef FLM_RING_ZERO_NLM if( RC_OK( m_rc)) { pszName = m_szFileName; } #else FLMUINT uiLength; if( RC_OK( m_rc)) { if( !m_FindData.pCurrentItem) { return( NULL); } uiLength = sizeof( m_FindData.ucTempBuffer) - 1; if( m_FindData.pCurrentItem->DFileNameLength < uiLength) { uiLength = m_FindData.pCurrentItem->DFileNameLength; } f_strncpy( m_FindData.ucTempBuffer, (const char *)m_FindData.pCurrentItem->DFileName, uiLength); m_FindData.ucTempBuffer[ uiLength] = 0; pszName = m_FindData.ucTempBuffer; } #endif return( pszName); } /**************************************************************************** Desc: ****************************************************************************/ FINLINE void FTKAPI F_DirHdl::currentItemPath( char * pszPath) { if( RC_OK( m_rc)) { f_strcpy( pszPath, m_szDirectoryPath); #ifdef FLM_RING_ZERO_NLM f_pathAppend( pszPath, currentItemName()); #else f_pathAppend( pszPath, m_szFileName); #endif } } /**************************************************************************** Desc: ****************************************************************************/ FLMBOOL FTKAPI F_DirHdl::currentItemIsDir( void) { #if defined( FLM_WIN) || defined( FLM_UNIX) || defined( FLM_LIBC_NLM) return( ((m_uiAttrib & F_IO_FA_DIRECTORY) ? TRUE : FALSE)); #elif defined( FLM_RING_ZERO_NLM) if( !m_FindData.pCurrentItem) { return( FALSE); } return( (m_FindData.pCurrentItem->DFileAttributes & SUBDIRECTORY_BIT) ? TRUE : FALSE); #else #error Platform not supported #endif } /**************************************************************************** Desc: ****************************************************************************/ FLMUINT64 FTKAPI F_DirHdl::currentItemSize( void) { FLMUINT64 ui64Size = 0; if( RC_OK( m_rc)) { #if defined( FLM_WIN) ui64Size = (((FLMUINT64)m_FindData.findBuffer.nFileSizeHigh) << 32) + m_FindData.findBuffer.nFileSizeLow; #elif defined( FLM_UNIX) || defined ( FLM_LIBC_NLM) ui64Size = m_FindData.FileStat.st_size; #elif defined( FLM_RING_ZERO_NLM) char szTmpPath[ F_PATH_MAX_SIZE]; currentItemPath( szTmpPath); (void)f_getFileSysPtr()->getFileSize( szTmpPath, &ui64Size); #endif } return( ui64Size); } /**************************************************************************** Desc: Get the next item in a directory ****************************************************************************/ #if defined( FLM_WIN) || defined( FLM_UNIX) || defined( FLM_LIBC_NLM) RCODE FTKAPI F_DirHdl::next( void) { char szFoundPath[ F_PATH_MAX_SIZE]; char szDummyPath[ F_PATH_MAX_SIZE]; FLMUINT uiSearchAttributes; FLMUINT uiFoundAttrib; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( RC_BAD( m_rc)) { goto Exit; } uiSearchAttributes = F_IO_FA_NORMAL | F_IO_FA_RDONLY | F_IO_FA_ARCHIVE | F_IO_FA_DIRECTORY; for( ;;) { if( m_bFirstTime) { m_bFirstTime = FALSE; if( RC_BAD( m_rc = f_fileFindFirst( m_szDirectoryPath, uiSearchAttributes, &m_FindData, szFoundPath, &uiFoundAttrib))) { goto Exit; } m_bFindOpen = TRUE; m_uiAttrib = uiFoundAttrib; } else { if( RC_BAD( m_rc = f_fileFindNext( &m_FindData, szFoundPath, &uiFoundAttrib))) { goto Exit; } m_uiAttrib = uiFoundAttrib; } if( RC_BAD( m_rc = pFileSystem->pathReduce( szFoundPath, szDummyPath, m_szFileName))) { goto Exit; } if( pFileSystem->doesFileMatch( m_szFileName, m_szPattern)) { break; } } Exit: return( m_rc); } #endif /**************************************************************************** Desc: Get the next item in a directory ****************************************************************************/ #if defined( FLM_RING_ZERO_NLM) RCODE FTKAPI F_DirHdl::next( void) { LONG lError = 0; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( RC_BAD( m_rc)) { goto Exit; } for( ;;) { if( (lError = DirectorySearch( 0, m_FindData.lVolumeNumber, m_FindData.lDirectoryNumber, LONGNameSpace, m_FindData.lCurrentEntryNumber, (BYTE *)"\x02\xFF*", -1, &m_FindData.pCurrentItem, &m_FindData.lCurrentEntryNumber)) != 0) { if( (lError == ERR_NO_FILES_FOUND) || (lError == ERR_INVALID_PATH)) { m_rc = RC_SET( NE_FLM_IO_NO_MORE_FILES); } else { m_rc = f_mapPlatformError( lError, NE_FLM_READING_FILE); } break; } if( pFileSystem->doesFileMatch( (const char *)m_FindData.pCurrentItem->DFileName, m_szPattern)) { break; } } Exit: return( m_rc); } #endif /**************************************************************************** Desc: Open a directory ****************************************************************************/ #ifndef FLM_RING_ZERO_NLM RCODE FTKAPI F_DirHdl::openDir( const char * pszDirName, const char * pszPattern) { RCODE rc = NE_FLM_OK; m_rc = NE_FLM_OK; m_bFirstTime = TRUE; m_bFindOpen = FALSE; m_uiAttrib = 0; f_memset( &m_FindData, 0, sizeof( m_FindData)); f_strcpy( m_szDirectoryPath, pszDirName); if( pszPattern) { if( f_strlen( pszPattern) >= (FLMINT)sizeof( m_szPattern)) { rc = RC_SET( NE_FLM_MEM); goto Exit; } f_strcpy( m_szPattern, pszPattern); } else { m_szPattern[ 0] = 0; } Exit: return( rc); } #endif /**************************************************************************** Desc: Open a directory Notes: 1. DOS file names, not long file names ! If we want to support long file names, then increase the size of the filename buffer and change the name space. 2. '*.*' doesn't work as a pattern. '*' seems to do the trick. 3. These Netware APIs are case sensitive. If you want to specify a a pattern like "*.db" make sure that the files you are looking for were created with lowercase "db" extensions. The path needs to match the case also. For example, sys:\_netware won't work. SYS:\_NETWARE will. 4. Server names are not supported by ConvertPathString 'Connecting to remote servers' is not supported by this code. ****************************************************************************/ #ifdef FLM_RING_ZERO_NLM RCODE FTKAPI F_DirHdl::openDir( const char * pszDirName, const char * pszPattern) { RCODE rc = NE_FLM_OK; LONG lError = 0; LONG unused; FLMBYTE pseudoLNamePath[ F_PATH_MAX_SIZE + 1]; FLMBYTE LNamePath[ F_PATH_MAX_SIZE]; LONG lLNamePathCount; m_rc = NE_FLM_OK; m_bFirstTime = TRUE; m_bFindOpen = FALSE; m_uiAttrib = 0; f_strcpy( m_szDirectoryPath, pszDirName); f_memset( &m_FindData, 0, sizeof( m_FindData)); m_FindData.lVolumeNumber = F_NW_DEFAULT_VOLUME_NUMBER; m_FindData.lCurrentEntryNumber = 0xFFFFFFFF; m_FindData.lDirectoryNumber = 0xFFFFFFFF; LNamePath[0] = 0; lLNamePathCount = 0; f_strcpy( (char *)&pseudoLNamePath[1], pszDirName); pseudoLNamePath[ 0] = (FLMBYTE)f_strlen( (const char *)&pseudoLNamePath[ 1]); if( (lError = ConvertPathString( 0, 0, pseudoLNamePath, &m_FindData.lVolumeNumber, &unused, (BYTE *)LNamePath, &lLNamePathCount)) != 0) { goto Exit; } if( (lError = MapPathToDirectoryNumber( 0, m_FindData.lVolumeNumber, 0, (BYTE *)LNamePath, lLNamePathCount, LONGNameSpace, &m_FindData.lDirectoryNumber, &unused)) != 0) { goto Exit; } if( pszPattern) { if( f_strlen( pszPattern) >= (FLMINT)sizeof( m_szPattern)) { rc = RC_SET( NE_FLM_MEM); goto Exit; } f_strcpy( m_szPattern, pszPattern); } else { m_szPattern[ 0] = 0; } Exit: if( lError != 0) { m_rc = f_mapPlatformError( lError, NE_FLM_OPENING_FILE); } return( m_rc); } #endif /**************************************************************************** Desc: Create a directory (and parent directories if necessary). ****************************************************************************/ #if defined( FLM_WIN) || defined( FLM_UNIX) || defined( FLM_LIBC_NLM) RCODE FTKAPI F_DirHdl::createDir( const char * pszDirPath) { RCODE rc = NE_FLM_OK; char * pszParentDir = NULL; IF_FileSystem * pFileSystem = f_getFileSysPtr(); 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 = pFileSystem->pathReduce( pszDirPath, pszParentDir, NULL))) { goto Exit; } // If pathReduce couldn't reduce the path at all, then an // invalid path was supplied. if( f_strcmp( pszDirPath, pszParentDir) == 0) { rc = RC_SET( NE_FLM_IO_INVALID_FILENAME); 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( pFileSystem->doesFileExist( pszParentDir))) { if( !pFileSystem->isDir( pszParentDir)) { rc = RC_SET( NE_FLM_IO_ACCESS_DENIED); goto Exit; } } else if( RC_BAD( rc = createDir( pszParentDir))) { goto Exit; } } #if defined( FLM_WIN) if( !CreateDirectory((LPTSTR)pszDirPath, NULL)) { rc = f_mapPlatformError( GetLastError(), NE_FLM_CREATING_FILE); } #elif defined( FLM_UNIX) || defined( FLM_LIBC_NLM) if( mkdir( (char *)pszDirPath, 0777) == -1) { rc = f_mapPlatformError( errno, NE_FLM_CREATING_FILE); } #endif Exit: if( pszParentDir) { f_free( &pszParentDir); } return( rc); } #endif /**************************************************************************** Desc: ****************************************************************************/ #if defined( FLM_RING_ZERO_NLM) RCODE FTKAPI F_DirHdl::createDir( const char * pszDirPath) { RCODE rc = NE_FLM_OK; 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; 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 = CreateDirectory( 0, lVolumeID, lPathID, pucLNamePath, lLNamePathCount, LONGNameSpace, MaximumDirectoryAccessBits, &lNewDirectoryID, &pNotUsed)) != 0) { goto Exit; } Exit: if( lErrorCode) { rc = f_mapPlatformError( lErrorCode, NE_FLM_CREATING_FILE); } return( rc); } #endif /**************************************************************************** Desc: Remove a directory Notes: The directory must be empty. ****************************************************************************/ RCODE FTKAPI F_DirHdl::removeDir( const char * pszDirName) { #if defined( FLM_WIN) if( !RemoveDirectory((LPTSTR)pszDirName)) { return( f_mapPlatformError( GetLastError(), NE_FLM_IO_DELETING_FILE)); } return( NE_FLM_OK); #elif defined( FLM_UNIX) || defined( FLM_LIBC_NLM) if( rmdir( (char *)pszDirName) == -1) { return( f_mapPlatformError( errno, NE_FLM_IO_DELETING_FILE)); } return( NE_FLM_OK); #elif defined( FLM_RING_ZERO_NLM) return( f_netwareRemoveDir( pszDirName)); #endif } /**************************************************************************** Desc: ****************************************************************************/ #if defined( FLM_RING_ZERO_NLM) RCODE f_netwareRemoveDir( const char * pszDirName) { RCODE rc = NE_FLM_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], pszDirName); pucPseudoLNamePath[0] = (FLMBYTE)f_strlen( pszDirName); 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 = f_mapPlatformError( lErrorCode, NE_FLM_IO_DELETING_FILE); } return( rc); } #endif /**************************************************************************** Desc: Find the first file that matches the supplied criteria ****************************************************************************/ #ifdef FLM_WIN RCODE f_fileFindFirst( char * pszSearchPath, FLMUINT uiSearchAttrib, F_IO_FIND_DATA * pFindData, char * pszFoundPath, FLMUINT * puiFoundAttrib) { RCODE rc = NE_FLM_OK; char szTmpPath[ F_PATH_MAX_SIZE]; char * pszWildCard = "*.*"; IF_FileSystem * pFileSystem = f_getFileSysPtr(); f_memset( pFindData, 0, sizeof( F_IO_FIND_DATA)); pFindData->findHandle = INVALID_HANDLE_VALUE; pFindData->uiSearchAttrib = uiSearchAttrib; if( !pszSearchPath) { rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND); goto Exit; } f_strcpy( pFindData->szSearchPath, pszSearchPath); if( uiSearchAttrib & F_IO_FA_NORMAL ) { uiSearchAttrib |= F_IO_FA_ARCHIVE; } f_strcpy( szTmpPath, pszSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( szTmpPath, pszWildCard))) { goto Exit; } if( (pFindData->findHandle = FindFirstFile( (LPTSTR)szTmpPath, &(pFindData->findBuffer))) == INVALID_HANDLE_VALUE) { rc = f_mapPlatformError( GetLastError(), NE_FLM_OPENING_FILE); goto Exit; } // Loop until a file with correct attributes is found for( ;;) { if( f_fileMeetsFindCriteria( pFindData)) { break; } if( FindNextFile( pFindData->findHandle, &(pFindData->findBuffer)) == FALSE) { rc = f_mapPlatformError( GetLastError(), NE_FLM_READING_FILE); goto Exit; } } // Append the file name to the path name f_strcpy( pszFoundPath, pFindData->szSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( pszFoundPath, (char *)pFindData->findBuffer.cFileName))) { goto Exit; } // Return the found file attribute *puiFoundAttrib = pFindData->findBuffer.dwFileAttributes; Exit: if( RC_BAD( rc) && pFindData && pFindData->findHandle != INVALID_HANDLE_VALUE) { f_fileFindClose( pFindData); } return( rc); } #endif /**************************************************************************** Desc: Find the first file that matches the supplied criteria ****************************************************************************/ #if defined( FLM_UNIX) || defined( FLM_LIBC_NLM) RCODE f_fileFindFirst( char * pszSearchPath, FLMUINT uiSearchAttrib, F_IO_FIND_DATA * pFindData, char * pszFoundPath, FLMUINT * puiFoundAttrib) { RCODE rc = NE_FLM_OK; char szTmpPath[ F_PATH_MAX_SIZE]; FSTATIC char pszWildCard[] = {'*',0}; int iRetVal; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( !pszSearchPath) { rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND); goto Exit; } f_strcpy( szTmpPath, pszSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( szTmpPath, pszWildCard))) { goto Exit; } f_memset( pFindData, 0, sizeof( F_IO_FIND_DATA)); if( uiSearchAttrib & F_IO_FA_DIRECTORY) { pFindData->mode_flag |= S_IFDIR; } if( uiSearchAttrib & F_IO_FA_RDONLY) { pFindData->mode_flag |= S_IREAD; } iRetVal = Find1( (char*)szTmpPath, pFindData); if( iRetVal != 0) { // If there were no more files found then return no more files // instead of mapping to error path not found or io error. // To return no more files ret_val is ENOENT (set in Find2) // and errno is not set if( iRetVal == ENOENT && errno == 0) { rc = RC_SET( NE_FLM_IO_NO_MORE_FILES); } else { rc = f_mapPlatformError( errno, NE_FLM_READING_FILE); } goto Exit; } // filter out ".." (PARENT) and "." (CURRENT) directories if( uiSearchAttrib & F_IO_FA_DIRECTORY ) { while( (f_strcmp( pFindData->name, "..") == 0) || (f_strcmp( pFindData->name, ".") == 0)) { if( (iRetVal = Find2( pFindData)) != 0) { // If there were no more files found then return no more files // instead of mapping to error path not found or io error. // To return no more files ret_val is ENOENT (set in Find2) // and errno is not set if( iRetVal == ENOENT && errno == 0) { rc = RC_SET( NE_FLM_IO_NO_MORE_FILES); } else { rc = f_mapPlatformError( errno, NE_FLM_READING_FILE); } goto Exit; } } } // Append the file name to the path name f_strcpy( pszFoundPath, pszSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( pszFoundPath, (char *)pFindData->name))) { goto Exit; } *puiFoundAttrib = (FLMUINT)ReturnAttributes( pFindData->FileStat.st_mode, pszFoundPath); // Save the search path in the NE_FLM_IO_FIND_DATA struct // for a find next call f_strcpy( pFindData->search_path, pszSearchPath); Exit: return( rc); } #endif /**************************************************************************** Desc: Find the next file that matches the supplied criteria ****************************************************************************/ #ifdef FLM_WIN RCODE f_fileFindNext( F_IO_FIND_DATA * pFindData, char * pszFoundPath, FLMUINT * puiFoundAttrib) { RCODE rc = NE_FLM_OK; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( FindNextFile( pFindData->findHandle, &(pFindData->findBuffer)) == FALSE) { rc = f_mapPlatformError( GetLastError(), NE_FLM_READING_FILE); goto Exit; } // Loop until a file with correct attributes is found for( ;;) { if( f_fileMeetsFindCriteria( pFindData)) { break; } if( FindNextFile( pFindData->findHandle, &(pFindData->findBuffer)) == FALSE) { rc = f_mapPlatformError( GetLastError(), NE_FLM_READING_FILE); goto Exit; } } // Append the file name to the path name f_strcpy( pszFoundPath, pFindData->szSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( pszFoundPath, (char *)pFindData->findBuffer.cFileName))) { goto Exit; } // Return the found file attribute *puiFoundAttrib = pFindData->findBuffer.dwFileAttributes; Exit: return( rc); } #endif /**************************************************************************** Desc: Find the next file that matches the supplied criteria ****************************************************************************/ #if defined( FLM_UNIX) || defined( FLM_LIBC_NLM) RCODE f_fileFindNext( F_IO_FIND_DATA * pFindData, char * pszFoundPath, FLMUINT * puiFoundAttrib) { RCODE rc = NE_FLM_OK; IF_FileSystem * pFileSystem = f_getFileSysPtr(); int iRetVal; if( (iRetVal = Find2( pFindData)) != 0) { // If there were no more files found then return no more files // instead of mapping to error path not found or io error. // To return no more files ret_val is ENOENT (set in Find2) // and errno is not set if( iRetVal == ENOENT && errno == 0) { return( RC_SET( NE_FLM_IO_NO_MORE_FILES)); } return( f_mapPlatformError( errno, NE_FLM_READING_FILE)); } // Append the file name to the path name f_strcpy( pszFoundPath, pFindData->search_path); if( RC_BAD( rc = pFileSystem->pathAppend( pszFoundPath, (char *)pFindData->name))) { goto Exit; } *puiFoundAttrib = (FLMUINT)ReturnAttributes( pFindData->FileStat.st_mode, pszFoundPath); Exit: return( rc); } #endif /**************************************************************************** Desc: Releases any memory allocated to an F_IO_FIND_DATA structure ****************************************************************************/ #ifdef FLM_WIN void f_fileFindClose( F_IO_FIND_DATA * pFindData) { // Don't call it on an already closed or invalid handle. if( pFindData->findHandle != INVALID_HANDLE_VALUE) { FindClose( pFindData->findHandle ); pFindData->findHandle = INVALID_HANDLE_VALUE; } } #endif /**************************************************************************** Desc: ****************************************************************************/ #if defined( FLM_UNIX) || defined ( FLM_LIBC_NLM) void f_fileFindClose( F_IO_FIND_DATA * pFindData) { if( pFindData->globbuf.gl_pathv) { pFindData->globbuf.gl_offs = 0; globfree( &pFindData->globbuf); pFindData->globbuf.gl_pathv = 0; } } #endif /**************************************************************************** Desc: Find the next file that matches the supplied criteria ****************************************************************************/ #ifdef FLM_WIN FSTATIC FLMBOOL f_fileMeetsFindCriteria( F_IO_FIND_DATA * pFindData) { // Fail ".." (PARENT) and "." (CURRENT) directories. Then, // if the file found possesses any of the search attributes, it's // a match. if( !((f_strcmp( pFindData->findBuffer.cFileName, "..") == 0) || (f_strcmp( pFindData->findBuffer.cFileName, ".") == 0) || (!(pFindData->uiSearchAttrib & F_IO_FA_DIRECTORY) && (pFindData->findBuffer.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))) { if( (pFindData->findBuffer.dwFileAttributes & pFindData->uiSearchAttrib) || ((pFindData->uiSearchAttrib & F_IO_FA_NORMAL) && (pFindData->findBuffer.dwFileAttributes == 0))) { return( TRUE); } } return( FALSE); } #endif /**************************************************************************** Desc: Search for file names matching FindTemplate (UNIX) ****************************************************************************/ #if defined( FLM_UNIX) || defined( FLM_LIBC_NLM) FSTATIC int Find1( char * FindTemplate, F_IO_FIND_DATA * DirInfo) { char MaskNam[ F_PATH_MAX_SIZE]; char *PathSeparator; FLMINT uiFindLen; FLMINT uiLen; #ifdef FLM_LIBC_NLM char szPosixNam[ F_PATH_MAX_SIZE]; FLMINT uiCount; #endif // If supplied template is illegal, return immediately if( (FindTemplate == NULL) || (uiFindLen = f_strlen( FindTemplate)) == 0) { return( EINVAL); } // Now separate the template into a PATH and a template MASK // If no separating slash character found, use current directory // as path! f_strcpy( DirInfo->full_path, FindTemplate); #ifdef FLM_LIBC_NLM if( (( PathSeparator = strrchr( DirInfo->full_path, '/')) == NULL) && ( PathSeparator = strrchr( DirInfo->full_path, '\\')) == NULL) #else if( (PathSeparator = strrchr( DirInfo->full_path, '/')) == NULL) #endif { (void) getcwd( DirInfo->full_path, F_PATH_MAX_SIZE); uiLen = f_strlen( DirInfo->full_path ); DirInfo->full_path[uiLen] = '/'; DirInfo->full_path[uiLen+1] = '\0'; (void) f_strcat( DirInfo->full_path, FindTemplate ); PathSeparator = strrchr( DirInfo->full_path, '/'); } // Copy the template MASK, and null terminate the PATH f_strcpy( MaskNam, PathSeparator + 1); if( ! f_strlen(MaskNam)) { (void) f_strcpy( MaskNam, "*"); } *PathSeparator = '\0'; // Use ROOT directory if PATH is empty if( ! f_strlen(DirInfo->full_path)) { (void) f_strcpy( DirInfo->full_path, "/"); } f_strcpy( DirInfo->dirpath, DirInfo->full_path ); // Open the specified directory. Return immediately // if error detected! errno = 0; DirInfo->globbuf.gl_pathv = 0; #ifdef FLM_LIBC_NLM // glob does not seem to be able to handle a non-posix path // on NetWare. for( uiCount = 0; uiCount <= uiFindLen; uiCount++) { if( FindTemplate[ uiCount] == '\\') { szPosixNam[ uiCount] = '/'; } else { szPosixNam[ uiCount] = FindTemplate[ uiCount]; } } if( glob( szPosixNam, GLOB_NOSORT, 0, &DirInfo->globbuf) != 0 && !DirInfo->globbuf.gl_pathc) #else if( glob( FindTemplate, GLOB_NOSORT, 0, &DirInfo->globbuf) != 0 && !DirInfo->globbuf.gl_pathc) #endif { globfree(&DirInfo->globbuf); DirInfo->globbuf.gl_pathv = 0; return ENOENT; } // Call Find2 to get the 1st matching file return( Find2(DirInfo) ); } #endif /**************************************************************************** Desc: Search for file names matching FindTemplate (UNIX) ****************************************************************************/ #if defined( FLM_UNIX) || defined( FLM_LIBC_NLM) FSTATIC int Find2( F_IO_FIND_DATA * DirStuff) { int stat; glob_t * pglob = &DirStuff->globbuf; char * pszTmp; char * pszLastSlash; errno = 0; for( ;;) { if( pglob->gl_offs == pglob->gl_pathc) { pglob->gl_offs = 0; globfree(pglob); pglob->gl_pathv = 0; return ENOENT; } // Get status of file f_strcpy(DirStuff->full_path, pglob->gl_pathv[pglob->gl_offs++]); if( (stat = RetrieveFileStat( DirStuff->full_path, &DirStuff->FileStat)) != 0 ) { // If file name just read from directory is NO // longer there (deleted by another process) // then just advance to the next file in // directory! if( stat == ENOENT) { continue; } else { break; } } // If we don't want directories, and current entry // is a directory, then skip it! if( (! S_ISDIR(DirStuff->mode_flag)) && S_ISDIR(DirStuff->FileStat.st_mode)) { continue; } // If we only want regular files and file is NOT // regular, then skip it! This means there is no // way to retrieve named pipes, sockets, or links! if ( (DirStuff->mode_flag == F_IO_FA_NORMAL) && (! S_ISREG(DirStuff->FileStat.st_mode)) ) { continue; } pszTmp = &DirStuff->full_path[ 0]; pszLastSlash = NULL; while( *pszTmp) { if( *pszTmp == '/') { pszLastSlash = pszTmp; } pszTmp++; } if( pszLastSlash) { f_strcpy( DirStuff->name, &pszLastSlash[ 1]); } else { f_strcpy( DirStuff->name, DirStuff->full_path); } stat = 0; break; } return( stat); } #endif /**************************************************************************** Desc: Return file's attributes (UNIX) ****************************************************************************/ #if defined( FLM_UNIX) || defined( FLM_LIBC_NLM) FSTATIC FLMBYTE ReturnAttributes( mode_t FileMode, char * fileName) { FLMBYTE IOmode = 0; // Return the found file attribute if( S_ISDIR( FileMode ) ) { IOmode |= F_IO_FA_DIRECTORY; } else { if( access( (char *)fileName, (int)(R_OK | W_OK)) == 0) { IOmode |= F_IO_FA_NORMAL; } else if( access( (char *)fileName, (int)R_OK ) == 0) { IOmode |= F_IO_FA_RDONLY; } } return( IOmode); } #endif /**************************************************************************** Desc: Return file's attributes (UNIX) || (NetWare) ****************************************************************************/ #if defined( FLM_UNIX) || defined( FLM_LIBC_NLM) FSTATIC int RetrieveFileStat( char * FilePath, struct stat * StatusRec) { // Get status of last file read from directory, using the standard // UNIX stat call errno = 0; if( stat( FilePath, StatusRec ) == -1) { if( errno == ENOENT || errno == ELOOP) { // Get status of symbolic link rather than referenced file! errno = 0; if( lstat( FilePath, StatusRec ) == -1) { return( errno); } } else { return( errno); } } return( 0); } #endif