OGRErr OGRGeoconceptDriver::DeleteDataSource( const char *pszDataSource ) { VSIStatBufL sStatBuf; static const char * const apszExtensions[] = { "gxt", "txt", "gct", "gcm", "gcr", nullptr }; if( VSIStatL( pszDataSource, &sStatBuf ) != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "%s does not appear to be a file or directory.", pszDataSource ); return OGRERR_FAILURE; } if( VSI_ISREG(sStatBuf.st_mode) && ( EQUAL(CPLGetExtension(pszDataSource),"gxt") || EQUAL(CPLGetExtension(pszDataSource),"txt") ) ) { for( int iExt=0; apszExtensions[iExt] != nullptr; iExt++ ) { const char *pszFile = CPLResetExtension(pszDataSource, apszExtensions[iExt] ); if( VSIStatL( pszFile, &sStatBuf ) == 0 ) VSIUnlink( pszFile ); } } else if( VSI_ISDIR(sStatBuf.st_mode) ) { char **papszDirEntries = VSIReadDir( pszDataSource ); for( int iFile = 0; papszDirEntries != nullptr && papszDirEntries[iFile] != nullptr; iFile++ ) { if( CSLFindString( const_cast<char **>( apszExtensions ), CPLGetExtension(papszDirEntries[iFile])) != -1) { VSIUnlink( CPLFormFilename( pszDataSource, papszDirEntries[iFile], nullptr ) ); } } CSLDestroy( papszDirEntries ); VSIRmdir( pszDataSource ); } return OGRERR_NONE; }
static void ProcessIdentifyTarget( const char *pszTarget, char **papszSiblingList, bool bRecursive, bool bReportFailures, bool bForceRecurse ) { GDALDriverH hDriver; VSIStatBufL sStatBuf; int i; hDriver = GDALIdentifyDriver( pszTarget, papszSiblingList ); if( hDriver != nullptr ) printf( "%s: %s\n", pszTarget, GDALGetDriverShortName( hDriver ) ); else if( bReportFailures ) printf( "%s: unrecognized\n", pszTarget ); if( !bForceRecurse && (!bRecursive || hDriver != nullptr) ) return; if( VSIStatL( pszTarget, &sStatBuf ) != 0 || !VSI_ISDIR( sStatBuf.st_mode ) ) return; papszSiblingList = VSIReadDir( pszTarget ); for( i = 0; papszSiblingList && papszSiblingList[i]; i++ ) { if( EQUAL(papszSiblingList[i],"..") || EQUAL(papszSiblingList[i],".") ) continue; CPLString osSubTarget = CPLFormFilename( pszTarget, papszSiblingList[i], nullptr ); ProcessIdentifyTarget( osSubTarget, papszSiblingList, bRecursive, bReportFailures, bForceRecurse ); } CSLDestroy(papszSiblingList); }
void OGRTigerDataSource::DeleteModuleFiles( const char *pszModule ) { char **papszDirFiles = VSIReadDir( GetDirPath() ); const int nCount = CSLCount(papszDirFiles); for( int i = 0; i < nCount; i++ ) { if( EQUALN(pszModule,papszDirFiles[i],strlen(pszModule)) ) { const char *pszFilename = CPLFormFilename( GetDirPath(), papszDirFiles[i], nullptr ); if( VSIUnlink( pszFilename ) != 0 ) { CPLDebug( "OGR_TIGER", "Failed to unlink %s", pszFilename ); } } } CSLDestroy( papszDirFiles ); }
int OGRTABDataSource::Open( GDALOpenInfo *poOpenInfo, int bTestOpen ) { CPLAssert(m_pszName == nullptr); m_pszName = CPLStrdup(poOpenInfo->pszFilename); m_bUpdate = poOpenInfo->eAccess == GA_Update; // If it is a file, try to open as a Mapinfo file. if( !poOpenInfo->bIsDirectory ) { IMapInfoFile *poFile = IMapInfoFile::SmartOpen(m_pszName, m_bUpdate, bTestOpen); if( poFile == nullptr ) return FALSE; poFile->SetDescription(poFile->GetName()); m_nLayerCount = 1; m_papoLayers = static_cast<IMapInfoFile **>(CPLMalloc(sizeof(void *))); m_papoLayers[0] = poFile; m_pszDirectory = CPLStrdup(CPLGetPath(m_pszName)); m_bSingleFile = TRUE; m_bSingleLayerAlreadyCreated = TRUE; } // Otherwise, we need to scan the whole directory for files // ending in .tab or .mif. else { char **papszFileList = VSIReadDir(m_pszName); m_pszDirectory = CPLStrdup(m_pszName); for( int iFile = 0; papszFileList != nullptr && papszFileList[iFile] != nullptr; iFile++ ) { const char *pszExtension = CPLGetExtension(papszFileList[iFile]); if( !EQUAL(pszExtension, "tab") && !EQUAL(pszExtension, "mif") ) continue; char *pszSubFilename = CPLStrdup( CPLFormFilename(m_pszDirectory, papszFileList[iFile], nullptr)); IMapInfoFile *poFile = IMapInfoFile::SmartOpen(pszSubFilename, m_bUpdate, bTestOpen); CPLFree(pszSubFilename); if( poFile == nullptr ) { CSLDestroy(papszFileList); return FALSE; } poFile->SetDescription( poFile->GetName() ); m_nLayerCount++; m_papoLayers = static_cast<IMapInfoFile **>( CPLRealloc(m_papoLayers,sizeof(void *) * m_nLayerCount)); m_papoLayers[m_nLayerCount-1] = poFile; } CSLDestroy(papszFileList); if( m_nLayerCount == 0 ) { if( !bTestOpen ) CPLError(CE_Failure, CPLE_OpenFailed, "No mapinfo files found in directory %s.", m_pszDirectory); return FALSE; } } return TRUE; }
int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn, int bForceOpen, char** papszOpenOptions ) { pszName = CPLStrdup( pszFilename ); bUpdate = bUpdateIn; if (bUpdateIn && bForceOpen && EQUAL(pszFilename, "/vsistdout/")) return TRUE; /* For writable /vsizip/, do nothing more */ if (bUpdateIn && bForceOpen && strncmp(pszFilename, "/vsizip/", 8) == 0) return TRUE; CPLString osFilename(pszFilename); CPLString osBaseFilename = CPLGetFilename(pszFilename); CPLString osExt = GetRealExtension(osFilename); pszFilename = NULL; int bIgnoreExtension = EQUALN(osFilename, "CSV:", 4); int bUSGeonamesFile = FALSE; /* int bGeonamesOrgFile = FALSE; */ if (bIgnoreExtension) { osFilename = osFilename + 4; } /* Those are *not* real .XLS files, but text file with tab as column separator */ if (EQUAL(osBaseFilename, "NfdcFacilities.xls") || EQUAL(osBaseFilename, "NfdcRunways.xls") || EQUAL(osBaseFilename, "NfdcRemarks.xls") || EQUAL(osBaseFilename, "NfdcSchedules.xls")) { if (bUpdateIn) return FALSE; bIgnoreExtension = TRUE; } else if ((EQUALN(osBaseFilename, "NationalFile_", 13) || EQUALN(osBaseFilename, "POP_PLACES_", 11) || EQUALN(osBaseFilename, "HIST_FEATURES_", 14) || EQUALN(osBaseFilename, "US_CONCISE_", 11) || EQUALN(osBaseFilename, "AllNames_", 9) || EQUALN(osBaseFilename, "Feature_Description_History_", 28) || EQUALN(osBaseFilename, "ANTARCTICA_", 11) || EQUALN(osBaseFilename, "GOVT_UNITS_", 11) || EQUALN(osBaseFilename, "NationalFedCodes_", 17) || EQUALN(osBaseFilename, "AllStates_", 10) || EQUALN(osBaseFilename, "AllStatesFedCodes_", 18) || (strlen(osBaseFilename) > 2 && EQUALN(osBaseFilename+2, "_Features_", 10)) || (strlen(osBaseFilename) > 2 && EQUALN(osBaseFilename+2, "_FedCodes_", 10))) && (EQUAL(osExt, "txt") || EQUAL(osExt, "zip")) ) { if (bUpdateIn) return FALSE; bIgnoreExtension = TRUE; bUSGeonamesFile = TRUE; if (EQUAL(osExt, "zip") && strstr(osFilename, "/vsizip/") == NULL ) { osFilename = "/vsizip/" + osFilename; } } else if (EQUAL(osBaseFilename, "allCountries.txt") || EQUAL(osBaseFilename, "allCountries.zip")) { if (bUpdateIn) return FALSE; bIgnoreExtension = TRUE; /* bGeonamesOrgFile = TRUE; */ if (EQUAL(osExt, "zip") && strstr(osFilename, "/vsizip/") == NULL ) { osFilename = "/vsizip/" + osFilename; } } /* -------------------------------------------------------------------- */ /* Determine what sort of object this is. */ /* -------------------------------------------------------------------- */ VSIStatBufL sStatBuf; if( VSIStatExL( osFilename, &sStatBuf, VSI_STAT_NATURE_FLAG ) != 0 ) return FALSE; /* -------------------------------------------------------------------- */ /* Is this a single CSV file? */ /* -------------------------------------------------------------------- */ if( VSI_ISREG(sStatBuf.st_mode) && (bIgnoreExtension || EQUAL(osExt,"csv") || EQUAL(osExt,"tsv")) ) { if (EQUAL(CPLGetFilename(osFilename), "NfdcFacilities.xls")) { return OpenTable( osFilename, papszOpenOptions, "ARP"); } else if (EQUAL(CPLGetFilename(osFilename), "NfdcRunways.xls")) { OpenTable( osFilename, papszOpenOptions, "BaseEndPhysical"); OpenTable( osFilename, papszOpenOptions, "BaseEndDisplaced"); OpenTable( osFilename, papszOpenOptions, "ReciprocalEndPhysical"); OpenTable( osFilename, papszOpenOptions, "ReciprocalEndDisplaced"); return nLayers != 0; } else if (bUSGeonamesFile) { /* GNIS specific */ if (EQUALN(osBaseFilename, "NationalFedCodes_", 17) || EQUALN(osBaseFilename, "AllStatesFedCodes_", 18) || EQUALN(osBaseFilename, "ANTARCTICA_", 11) || (strlen(osBaseFilename) > 2 && EQUALN(osBaseFilename+2, "_FedCodes_", 10))) { OpenTable( osFilename, papszOpenOptions, NULL, "PRIMARY"); } else if (EQUALN(osBaseFilename, "GOVT_UNITS_", 11) || EQUALN(osBaseFilename, "Feature_Description_History_", 28)) { OpenTable( osFilename, papszOpenOptions, NULL, ""); } else { OpenTable( osFilename, papszOpenOptions, NULL, "PRIM"); OpenTable( osFilename, papszOpenOptions, NULL, "SOURCE"); } return nLayers != 0; } return OpenTable( osFilename, papszOpenOptions ); } /* -------------------------------------------------------------------- */ /* Is this a single a ZIP file with only a CSV file inside ? */ /* -------------------------------------------------------------------- */ if( strncmp(osFilename, "/vsizip/", 8) == 0 && EQUAL(osExt, "zip") && VSI_ISREG(sStatBuf.st_mode) ) { char** papszFiles = VSIReadDir(osFilename); if (CSLCount(papszFiles) != 1 || !EQUAL(CPLGetExtension(papszFiles[0]), "CSV")) { CSLDestroy(papszFiles); return FALSE; } osFilename = CPLFormFilename(osFilename, papszFiles[0], NULL); CSLDestroy(papszFiles); return OpenTable( osFilename, papszOpenOptions ); } /* -------------------------------------------------------------------- */ /* Otherwise it has to be a directory. */ /* -------------------------------------------------------------------- */ if( !VSI_ISDIR(sStatBuf.st_mode) ) return FALSE; /* -------------------------------------------------------------------- */ /* Scan through for entries ending in .csv. */ /* -------------------------------------------------------------------- */ int nNotCSVCount = 0, i; char **papszNames = CPLReadDir( osFilename ); for( i = 0; papszNames != NULL && papszNames[i] != NULL; i++ ) { CPLString oSubFilename = CPLFormFilename( osFilename, papszNames[i], NULL ); if( EQUAL(papszNames[i],".") || EQUAL(papszNames[i],"..") ) continue; if (EQUAL(CPLGetExtension(oSubFilename),"csvt")) continue; if( VSIStatL( oSubFilename, &sStatBuf ) != 0 || !VSI_ISREG(sStatBuf.st_mode) ) { nNotCSVCount++; continue; } if (EQUAL(CPLGetExtension(oSubFilename),"csv")) { if( !OpenTable( oSubFilename, papszOpenOptions ) ) { CPLDebug("CSV", "Cannot open %s", oSubFilename.c_str()); nNotCSVCount++; continue; } } /* GNIS specific */ else if ( strlen(papszNames[i]) > 2 && EQUALN(papszNames[i]+2, "_Features_", 10) && EQUAL(CPLGetExtension(papszNames[i]), "txt") ) { int bRet = OpenTable( oSubFilename, papszOpenOptions, NULL, "PRIM"); bRet |= OpenTable( oSubFilename, papszOpenOptions, NULL, "SOURCE"); if ( !bRet ) { CPLDebug("CSV", "Cannot open %s", oSubFilename.c_str()); nNotCSVCount++; continue; } } /* GNIS specific */ else if ( strlen(papszNames[i]) > 2 && EQUALN(papszNames[i]+2, "_FedCodes_", 10) && EQUAL(CPLGetExtension(papszNames[i]), "txt") ) { if ( !OpenTable( oSubFilename, papszOpenOptions, NULL, "PRIMARY") ) { CPLDebug("CSV", "Cannot open %s", oSubFilename.c_str()); nNotCSVCount++; continue; } } else { nNotCSVCount++; continue; } } CSLDestroy( papszNames ); /* -------------------------------------------------------------------- */ /* We presume that this is indeed intended to be a CSV */ /* datasource if over half the files were .csv files. */ /* -------------------------------------------------------------------- */ return bForceOpen || nNotCSVCount < nLayers; }
int OGRSelafinDataSource::Open(const char * pszFilename, int bUpdateIn, int bCreate) { // Check if a range is set and extract it and the filename const char *pszc=pszFilename; if (*pszFilename==0) return FALSE; while (*pszc) ++pszc; if (*(pszc-1)==']') { --pszc; while (pszc!=pszFilename && *pszc!='[') pszc--; if (pszc==pszFilename) return FALSE; poRange.setRange(pszc); } pszName = CPLStrdup( pszFilename ); pszName[pszc-pszFilename]=0; bUpdate = bUpdateIn; if (bCreate && EQUAL(pszName, "/vsistdout/")) return TRUE; /* For writable /vsizip/, do nothing more */ if (bCreate && STARTS_WITH(pszName, "/vsizip/")) return TRUE; CPLString osFilename(pszName); CPLString osBaseFilename = CPLGetFilename(pszName); // Determine what sort of object this is. VSIStatBufL sStatBuf; if (VSIStatExL( osFilename, &sStatBuf, VSI_STAT_NATURE_FLAG ) != 0) return FALSE; // Is this a single Selafin file? if (VSI_ISREG(sStatBuf.st_mode)) return OpenTable( pszName ); // Is this a single a ZIP file with only a Selafin file inside ? if( STARTS_WITH(osFilename, "/vsizip/") && VSI_ISREG(sStatBuf.st_mode) ) { char** papszFiles = VSIReadDir(osFilename); if (CSLCount(papszFiles) != 1) { CSLDestroy(papszFiles); return FALSE; } osFilename = CPLFormFilename(osFilename, papszFiles[0], NULL); CSLDestroy(papszFiles); return OpenTable( osFilename ); } #ifdef notdef // Otherwise it has to be a directory. if( !VSI_ISDIR(sStatBuf.st_mode) ) return FALSE; // Scan through for entries which look like Selafin files int nNotSelafinCount = 0, i; char **papszNames = VSIReadDir( osFilename ); for( i = 0; papszNames != NULL && papszNames[i] != NULL; i++ ) { CPLString oSubFilename = CPLFormFilename( osFilename, papszNames[i], NULL ); if( EQUAL(papszNames[i],".") || EQUAL(papszNames[i],"..") ) continue; if( VSIStatL( oSubFilename, &sStatBuf ) != 0 || !VSI_ISREG(sStatBuf.st_mode) ) { nNotSelafinCount++; continue; } if( !OpenTable( oSubFilename ) ) { CPLDebug("Selafin", "Cannot open %s", oSubFilename.c_str()); nNotSelafinCount++; continue; } } CSLDestroy( papszNames ); // We presume that this is indeed intended to be a Selafin datasource if over half the files were Selafin files. return nNotSelafinCount < nLayers; #else return FALSE; #endif }
bool OGRShapeDataSource::Open( GDALOpenInfo* poOpenInfo, bool bTestOpen, bool bForceSingleFileDataSource ) { CPLAssert( nLayers == 0 ); const char * pszNewName = poOpenInfo->pszFilename; const bool bUpdate = poOpenInfo->eAccess == GA_Update; papszOpenOptions = CSLDuplicate( poOpenInfo->papszOpenOptions ); pszName = CPLStrdup( pszNewName ); bDSUpdate = bUpdate; bSingleFileDataSource = CPL_TO_BOOL(bForceSingleFileDataSource); /* -------------------------------------------------------------------- */ /* If bSingleFileDataSource is TRUE we don't try to do anything */ /* else. */ /* This is only utilized when the OGRShapeDriver::Create() */ /* method wants to create a stub OGRShapeDataSource for a */ /* single shapefile. The driver will take care of creating the */ /* file by calling ICreateLayer(). */ /* -------------------------------------------------------------------- */ if( bSingleFileDataSource ) return true; /* -------------------------------------------------------------------- */ /* Is the given path a directory or a regular file? */ /* -------------------------------------------------------------------- */ if( !poOpenInfo->bStatOK ) { if( !bTestOpen ) CPLError( CE_Failure, CPLE_AppDefined, "%s is neither a file or directory, Shape access failed.", pszNewName ); return false; } /* -------------------------------------------------------------------- */ /* Build a list of filenames we figure are Shape files. */ /* -------------------------------------------------------------------- */ if( !poOpenInfo->bIsDirectory ) { if( !OpenFile( pszNewName, bUpdate ) ) { if( !bTestOpen ) CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open shapefile %s. " "It may be corrupt or read-only file accessed in " "update mode.", pszNewName ); return false; } bSingleFileDataSource = true; return true; } else { char **papszCandidates = VSIReadDir( pszNewName ); const int nCandidateCount = CSLCount( papszCandidates ); bool bMightBeOldCoverage = false; std::set<CPLString> osLayerNameSet; for( int iCan = 0; iCan < nCandidateCount; iCan++ ) { const char *pszCandidate = papszCandidates[iCan]; const char *pszLayerName = CPLGetBasename(pszCandidate); CPLString osLayerName(pszLayerName); #ifdef WIN32 // On Windows, as filenames are case insensitive, a shapefile layer // can be made of foo.shp and FOO.DBF, so to detect unique layer // names, put them upper case in the unique set used for detection. osLayerName.toupper(); #endif if( EQUAL(pszCandidate,"ARC") ) bMightBeOldCoverage = true; if( strlen(pszCandidate) < 4 || !EQUAL(pszCandidate+strlen(pszCandidate)-4,".shp") ) continue; char *pszFilename = CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL)); osLayerNameSet.insert(osLayerName); #ifdef IMMEDIATE_OPENING if( !OpenFile( pszFilename, bUpdate ) && !bTestOpen ) { CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open shapefile %s. " "It may be corrupt or read-only file accessed in " "update mode.", pszFilename ); CPLFree( pszFilename ); CSLDestroy( papszCandidates ); return false; } #else oVectorLayerName.push_back(pszFilename); #endif CPLFree( pszFilename ); } // Try and .dbf files without apparent associated shapefiles. for( int iCan = 0; iCan < nCandidateCount; iCan++ ) { const char *pszCandidate = papszCandidates[iCan]; const char *pszLayerName = CPLGetBasename(pszCandidate); CPLString osLayerName(pszLayerName); #ifdef WIN32 osLayerName.toupper(); #endif // We don't consume .dbf files in a directory that looks like // an old style Arc/Info (for PC?) that unless we found at least // some shapefiles. See Bug 493. if( bMightBeOldCoverage && osLayerNameSet.size() == 0 ) continue; if( strlen(pszCandidate) < 4 || !EQUAL(pszCandidate+strlen(pszCandidate)-4, ".dbf") ) continue; if( osLayerNameSet.find(osLayerName) != osLayerNameSet.end() ) continue; // We don't want to access .dbf files with an associated .tab // file, or it will never get recognised as a mapinfo dataset. bool bFoundTAB = false; for( int iCan2 = 0; iCan2 < nCandidateCount; iCan2++ ) { const char *pszCandidate2 = papszCandidates[iCan2]; if( EQUALN(pszCandidate2, pszLayerName, strlen(pszLayerName)) && EQUAL(pszCandidate2 + strlen(pszLayerName), ".tab") ) bFoundTAB = true; } if( bFoundTAB ) continue; char *pszFilename = CPLStrdup(CPLFormFilename(pszNewName, pszCandidate, NULL)); osLayerNameSet.insert(osLayerName); #ifdef IMMEDIATE_OPENING if( !OpenFile( pszFilename, bUpdate ) && !bTestOpen ) { CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open dbf file %s. " "It may be corrupt or read-only file accessed in " "update mode.", pszFilename ); CPLFree( pszFilename ); CSLDestroy( papszCandidates ); return false; } #else oVectorLayerName.push_back(pszFilename); #endif CPLFree( pszFilename ); } CSLDestroy( papszCandidates ); #ifdef IMMEDIATE_OPENING const int nDirLayers = nLayers; #else const int nDirLayers = static_cast<int>(oVectorLayerName.size()); #endif CPLErrorReset(); return nDirLayers > 0 || !bTestOpen; } }
/********************************************************************** * TABAdjustCaseSensitiveFilename() * * Scan a filename and its path, adjust uppercase/lowercases if * necessary. * * Returns TRUE if file found, or FALSE if it could not be located with * a case-insensitive search. * * This function works on the original buffer and returns a reference to it. * It does nothing on Windows systems where filenames are not case sensitive. **********************************************************************/ static GBool TABAdjustCaseSensitiveFilename(char * #ifndef _WIN32 pszFname #endif ) { #ifdef _WIN32 /*----------------------------------------------------------------- * Nothing to do on Windows *----------------------------------------------------------------*/ return TRUE; #else /*----------------------------------------------------------------- * Unix case. *----------------------------------------------------------------*/ VSIStatBufL sStatBuf; char *pszTmpPath = NULL; int nTotalLen, iTmpPtr; GBool bValidPath; /*----------------------------------------------------------------- * First check if the filename is OK as is. *----------------------------------------------------------------*/ if (VSIStatL(pszFname, &sStatBuf) == 0) { return TRUE; } /*----------------------------------------------------------------- * OK, file either does not exist or has the wrong cases... we'll * go backwards until we find a portion of the path that is valid. *----------------------------------------------------------------*/ pszTmpPath = CPLStrdup(pszFname); nTotalLen = static_cast<int>(strlen(pszTmpPath)); iTmpPtr = nTotalLen; bValidPath = FALSE; while(iTmpPtr > 0 && !bValidPath) { /*------------------------------------------------------------- * Move back to the previous '/' separator *------------------------------------------------------------*/ pszTmpPath[--iTmpPtr] = '\0'; while( iTmpPtr > 0 && pszTmpPath[iTmpPtr-1] != '/' ) { pszTmpPath[--iTmpPtr] = '\0'; } if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) == 0) bValidPath = TRUE; } CPLAssert(iTmpPtr >= 0); /*----------------------------------------------------------------- * Assume that CWD is valid... so an empty path is a valid path *----------------------------------------------------------------*/ if (iTmpPtr == 0) bValidPath = TRUE; /*----------------------------------------------------------------- * OK, now that we have a valid base, reconstruct the whole path * by scanning all the sub-directories. * If we get to a point where a path component does not exist then * we simply return the rest of the path as is. *----------------------------------------------------------------*/ while(bValidPath && (int)strlen(pszTmpPath) < nTotalLen) { char **papszDir=NULL; int iEntry, iLastPartStart; iLastPartStart = iTmpPtr; papszDir = VSIReadDir(pszTmpPath); /*------------------------------------------------------------- * Add one component to the current path *------------------------------------------------------------*/ pszTmpPath[iTmpPtr] = pszFname[iTmpPtr]; iTmpPtr++; for( ; pszFname[iTmpPtr] != '\0' && pszFname[iTmpPtr]!='/'; iTmpPtr++) { pszTmpPath[iTmpPtr] = pszFname[iTmpPtr]; } while(iLastPartStart < iTmpPtr && pszTmpPath[iLastPartStart] == '/') iLastPartStart++; /*------------------------------------------------------------- * And do a case insensitive search in the current dir... *------------------------------------------------------------*/ for(iEntry=0; papszDir && papszDir[iEntry]; iEntry++) { if (EQUAL(pszTmpPath+iLastPartStart, papszDir[iEntry])) { /* Fount it! */ strcpy(pszTmpPath+iLastPartStart, papszDir[iEntry]); break; } } if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) != 0) bValidPath = FALSE; CSLDestroy(papszDir); } /*----------------------------------------------------------------- * We reached the last valid path component... just copy the rest * of the path as is. *----------------------------------------------------------------*/ if (iTmpPtr < nTotalLen-1) { strncpy(pszTmpPath+iTmpPtr, pszFname+iTmpPtr, nTotalLen-iTmpPtr); } /*----------------------------------------------------------------- * Update the source buffer and return. *----------------------------------------------------------------*/ strcpy(pszFname, pszTmpPath); CPLFree(pszTmpPath); return bValidPath; #endif }
GDALOpenInfo::GDALOpenInfo( const char * pszFilenameIn, GDALAccess eAccessIn, char **papszSiblingsIn ) { /* -------------------------------------------------------------------- */ /* Ensure that C: is treated as C:\ so we can stat it on */ /* Windows. Similar to what is done in CPLStat(). */ /* -------------------------------------------------------------------- */ #ifdef WIN32 if( strlen(pszFilenameIn) == 2 && pszFilenameIn[1] == ':' ) { char szAltPath[10]; strcpy( szAltPath, pszFilenameIn ); strcat( szAltPath, "\\" ); pszFilename = CPLStrdup( szAltPath ); } else #endif pszFilename = CPLStrdup( pszFilenameIn ); /* -------------------------------------------------------------------- */ /* Initialize. */ /* -------------------------------------------------------------------- */ nHeaderBytes = 0; pabyHeader = NULL; bIsDirectory = FALSE; bStatOK = FALSE; eAccess = eAccessIn; fp = NULL; /* -------------------------------------------------------------------- */ /* Collect information about the file. */ /* -------------------------------------------------------------------- */ VSIStatBufL sStat; if( VSIStatL( pszFilename, &sStat ) == 0 ) { bStatOK = TRUE; if( VSI_ISREG( sStat.st_mode ) ) { pabyHeader = (GByte *) CPLCalloc(1025,1); fp = VSIFOpen( pszFilename, "rb" ); if( fp != NULL ) { nHeaderBytes = (int) VSIFRead( pabyHeader, 1, 1024, fp ); VSIRewind( fp ); } /* XXX: ENOENT is used to catch the case of virtual filesystem * when we do not have a real file with such a name. Under some * circumstances EINVAL reported instead of ENOENT in Windows * (for filenames containing colon, e.g. "smth://name"). * See also: #2437 */ else if( errno == 27 /* "File to large" */ || errno == ENOENT || errno == EINVAL #ifdef EOVERFLOW || errno == EOVERFLOW #else || errno == 75 /* Linux EOVERFLOW */ || errno == 79 /* Solaris EOVERFLOW */ #endif ) { fp = VSIFOpenL( pszFilename, "rb" ); if( fp != NULL ) { nHeaderBytes = (int) VSIFReadL( pabyHeader, 1, 1024, fp ); VSIFCloseL( fp ); fp = NULL; } } } else if( VSI_ISDIR( sStat.st_mode ) ) bIsDirectory = TRUE; } /* -------------------------------------------------------------------- */ /* Capture sibling list either from passed in values, or by */ /* scanning for them. */ /* -------------------------------------------------------------------- */ if( papszSiblingsIn != NULL ) { papszSiblingFiles = CSLDuplicate( papszSiblingsIn ); } else if( bStatOK && !bIsDirectory ) { if( CSLTestBoolean( CPLGetConfigOption( "GDAL_DISABLE_READDIR_ON_OPEN", "NO" )) ) { /* skip reading the directory */ papszSiblingFiles = NULL; } else { CPLString osDir = CPLGetDirname( pszFilename ); papszSiblingFiles = VSIReadDir( osDir ); } } else papszSiblingFiles = NULL; }
GDALOpenInfo::GDALOpenInfo(const char *pszFilenameIn, GDALAccess eAccessIn, char **papszSiblingsIn) { /* -------------------------------------------------------------------- */ /* Ensure that C: is treated as C:\ so we can stat it on */ /* Windows. Similar to what is done in CPLStat(). */ /* -------------------------------------------------------------------- */ #ifdef WIN32 if (strlen(pszFilenameIn) == 2 && pszFilenameIn[1] == ':') { char szAltPath[10]; strcpy(szAltPath, pszFilenameIn); strcat(szAltPath, "\\"); pszFilename = CPLStrdup(szAltPath); } else #endif pszFilename = CPLStrdup(pszFilenameIn); /* -------------------------------------------------------------------- */ /* Initialize. */ /* -------------------------------------------------------------------- */ nHeaderBytes = 0; pabyHeader = NULL; bIsDirectory = FALSE; bStatOK = FALSE; eAccess = eAccessIn; fp = NULL; #ifdef HAVE_READLINK int bHasRetried = FALSE; #endif /* -------------------------------------------------------------------- */ /* Collect information about the file. */ /* -------------------------------------------------------------------- */ VSIStatBufL sStat; #ifdef HAVE_READLINK retry: #endif if (VSIStatExL(pszFilename, &sStat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0) { bStatOK = TRUE; if (VSI_ISREG(sStat.st_mode)) { pabyHeader = (GByte*) CPLCalloc(1025, 1); fp = VSIFOpen(pszFilename, "rb"); if (fp != NULL) { nHeaderBytes = (int) VSIFRead(pabyHeader, 1, 1024, fp); VSIRewind(fp); } /* XXX: ENOENT is used to catch the case of virtual filesystem * when we do not have a real file with such a name. Under some * circumstances EINVAL reported instead of ENOENT in Windows * (for filenames containing colon, e.g. "smth://name"). * See also: #2437 */ else if (errno == 27 /* "File to large" */ || errno == ENOENT || errno == EINVAL #ifdef EOVERFLOW || errno == EOVERFLOW #else || errno == 75 /* Linux EOVERFLOW */ || errno == 79 /* Solaris EOVERFLOW */ #endif ) { VSILFILE *fpL = VSIFOpenL(pszFilename, "rb"); if (fpL != NULL) { nHeaderBytes = (int) VSIFReadL(pabyHeader, 1, 1024, fpL); VSIFCloseL(fpL); } } } else if (VSI_ISDIR(sStat.st_mode)) bIsDirectory = TRUE; } #ifdef HAVE_READLINK else if (!bHasRetried) { /* If someone creates a file with "ln -sf /vsicurl/http://download.osgeo.org/gdal/data/gtiff/utm.tif my_remote_utm.tif" */ /* we will be able to open it by passing my_remote_utm.tif */ /* This helps a lot for GDAL based readers that only provide file explorers to open datasets */ char szPointerFilename[2048]; int nBytes = readlink(pszFilename, szPointerFilename, sizeof(szPointerFilename)); if (nBytes != -1) { szPointerFilename[MIN(nBytes, (int)sizeof(szPointerFilename) - 1)] = 0; CPLFree(pszFilename); pszFilename = CPLStrdup(szPointerFilename); papszSiblingsIn = NULL; bHasRetried = TRUE; goto retry; } } #endif /* -------------------------------------------------------------------- */ /* Capture sibling list either from passed in values, or by */ /* scanning for them. */ /* -------------------------------------------------------------------- */ if (papszSiblingsIn != NULL) { papszSiblingFiles = CSLDuplicate(papszSiblingsIn); } else if (bStatOK && !bIsDirectory) { const char *pszOptionVal = CPLGetConfigOption("GDAL_DISABLE_READDIR_ON_OPEN", "NO"); if (EQUAL(pszOptionVal, "EMPTY_DIR")) { papszSiblingFiles = CSLAddString(NULL, CPLGetFilename(pszFilename)); } else if (CSLTestBoolean(pszOptionVal)) { /* skip reading the directory */ papszSiblingFiles = NULL; } else { CPLString osDir = CPLGetDirname(pszFilename); papszSiblingFiles = VSIReadDir(osDir); } } else papszSiblingFiles = NULL; }
int OGRTigerDataSource::Open( const char * pszFilename, int bTestOpen, char ** papszLimitedFileList ) { pszName = CPLStrdup( pszFilename ); /* -------------------------------------------------------------------- */ /* Is the given path a directory or a regular file? */ /* -------------------------------------------------------------------- */ VSIStatBufL stat; if( VSIStatExL( pszFilename, &stat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) ) { if( !bTestOpen ) CPLError( CE_Failure, CPLE_AppDefined, "%s is neither a file or directory, Tiger access failed.\n", pszFilename ); return FALSE; } /* -------------------------------------------------------------------- */ /* Build a list of filenames we figure are Tiger files. */ /* -------------------------------------------------------------------- */ char **papszFileList = nullptr; if( VSI_ISREG(stat.st_mode) ) { char szModule[128]; if( strlen(CPLGetFilename(pszFilename)) == 0 ) { return FALSE; } pszPath = CPLStrdup( CPLGetPath(pszFilename) ); strncpy( szModule, CPLGetFilename(pszFilename), sizeof(szModule)-1 ); /* Make sure the buffer is 0 terminated */ szModule[sizeof(szModule)-1] = '\0'; /* And now remove last character of filename */ szModule[strlen(szModule)-1] = '\0'; papszFileList = CSLAddString( papszFileList, szModule ); } else { char **candidateFileList = VSIReadDir( pszFilename ); pszPath = CPLStrdup( pszFilename ); for( int i = 0; candidateFileList != nullptr && candidateFileList[i] != nullptr; i++ ) { size_t nCandidateLen = strlen(candidateFileList[i]); if( papszLimitedFileList != nullptr && CSLFindString(papszLimitedFileList, CPLGetBasename(candidateFileList[i])) == -1 ) { continue; } if( nCandidateLen > 4 && candidateFileList[i][nCandidateLen-4] == '.' && candidateFileList[i][nCandidateLen-1] == '1') { char szModule[128]; snprintf( szModule, sizeof(szModule), "%s", candidateFileList[i] ); const size_t nLen = strlen(szModule); if( nLen ) szModule[nLen-1] = '\0'; papszFileList = CSLAddString(papszFileList, szModule); } } CSLDestroy( candidateFileList ); if( CSLCount(papszFileList) == 0 ) { if( !bTestOpen ) CPLError( CE_Failure, CPLE_OpenFailed, "No candidate Tiger files (TGR*.RT1) found in\n" "directory: %s", pszFilename ); CSLDestroy(papszFileList); return FALSE; } } /* -------------------------------------------------------------------- */ /* Loop over all these files trying to open them. In testopen */ /* mode we first read the first 80 characters, to verify that */ /* it looks like an Tiger file. Note that we don't keep the file */ /* open ... we don't want to occupy a lot of file handles when */ /* handling a whole directory. */ /* -------------------------------------------------------------------- */ papszModules = nullptr; for( int i = 0; papszFileList && papszFileList[i] != nullptr; i++ ) { if( bTestOpen || i == 0 ) { char *l_pszFilename = BuildFilename( papszFileList[i], "1" ); VSILFILE *fp = VSIFOpenL( l_pszFilename, "rb" ); CPLFree( l_pszFilename ); if( fp == nullptr ) continue; char szHeader[500] = {}; if( VSIFReadL( szHeader, sizeof(szHeader)-1, 1, fp ) < 1 ) { VSIFCloseL( fp ); continue; } VSIFCloseL( fp ); char *pszRecStart = szHeader; szHeader[sizeof(szHeader)-1] = '\0'; bool bIsGDT = false; if( STARTS_WITH_CI(pszRecStart, "Copyright (C)") && strstr(pszRecStart,"Geographic Data Tech") != nullptr ) { bIsGDT = true; while( *pszRecStart != '\0' && *pszRecStart != 10 && *pszRecStart != 13 ) pszRecStart++; while( *pszRecStart == 10 || *pszRecStart == 13 ) pszRecStart++; } if( pszRecStart[0] != '1' ) continue; if( !isdigit(pszRecStart[1]) || !isdigit(pszRecStart[2]) || !isdigit(pszRecStart[3]) || !isdigit(pszRecStart[4]) ) continue; nVersionCode = atoi(TigerFileBase::GetField( pszRecStart, 2, 5 )); nVersion = TigerClassifyVersion( nVersionCode ); nVersion = TigerCheckVersion( nVersion, papszFileList[i] ); CPLDebug( "OGR", "Tiger Version Code=%d, Classified as %s ", nVersionCode, TigerVersionString(nVersion) ); if( nVersionCode != 0 && nVersionCode != 2 && nVersionCode != 3 && nVersionCode != 5 && nVersionCode != 21 && nVersionCode != 24 && pszRecStart[3] != '9' && pszRecStart[3] != DIGIT_ZERO && !bIsGDT ) continue; // we could (and should) add a bunch more validation here. } papszModules = CSLAddString( papszModules, papszFileList[i] ); } CSLDestroy( papszFileList ); nModules = CSLCount( papszModules ); if( nModules == 0 || papszModules == nullptr ) { if( !bTestOpen ) { if( VSI_ISREG(stat.st_mode) ) CPLError( CE_Failure, CPLE_OpenFailed, "No TIGER/Line files (TGR*.RT1) found in\n" "directory: %s", pszFilename ); else CPLError( CE_Failure, CPLE_OpenFailed, "File %s does not appear to be a TIGER/Line .RT1 file.", pszFilename ); } return FALSE; } /* -------------------------------------------------------------------- */ /* Do we have a user provided version override? */ /* -------------------------------------------------------------------- */ const char *pszRequestedVersion = CPLGetConfigOption( "TIGER_VERSION", nullptr ); if( pszRequestedVersion != nullptr ) { if( STARTS_WITH_CI(pszRequestedVersion, "TIGER_") ) { int iCode = 1; // Used after for. for( ; iCode < TIGER_Unknown; iCode++ ) { if( EQUAL(TigerVersionString((TigerVersion)iCode), pszRequestedVersion) ) { nVersion = (TigerVersion) iCode; break; } } if( iCode == TIGER_Unknown ) { CPLError( CE_Failure, CPLE_AppDefined, "Failed to recognise TIGER_VERSION setting: %s", pszRequestedVersion ); return FALSE; } CPLDebug( "OGR", "OVERRIDE Tiger Version %s ", TigerVersionString(nVersion) ); } else { nVersionCode = atoi(pszRequestedVersion); nVersion = TigerClassifyVersion( nVersionCode ); CPLDebug( "OGR", "OVERRIDE Tiger Version Code=%d, Classified as %s ", nVersionCode, TigerVersionString(nVersion) ); } } /* -------------------------------------------------------------------- */ /* Create the layers which appear to exist. */ /* -------------------------------------------------------------------- */ // RT1, RT2, RT3 AddLayer( new OGRTigerLayer( this, new TigerCompleteChain( this, papszModules[0]) )); /* should we have kept track of whether we encountered an RT4 file? */ // RT4 AddLayer( new OGRTigerLayer( this, new TigerAltName( this, papszModules[0]) )); // RT5 AddLayer( new OGRTigerLayer( this, new TigerFeatureIds( this, papszModules[0]) )); // RT6 AddLayer( new OGRTigerLayer( this, new TigerZipCodes( this, papszModules[0]) )); // RT7 AddLayer( new OGRTigerLayer( this, new TigerLandmarks( this, papszModules[0]) )); // RT8 AddLayer( new OGRTigerLayer( this, new TigerAreaLandmarks( this, papszModules[0]) )); // RT9 if (nVersion < TIGER_2002) { AddLayer( new OGRTigerLayer( this, new TigerKeyFeatures( this, papszModules[0]) )); } // RTA, RTS AddLayer( new OGRTigerLayer( this, new TigerPolygon( this, papszModules[0]) )); // RTB if (nVersion >= TIGER_2002) { AddLayer( new OGRTigerLayer( this, new TigerPolygonCorrections( this, papszModules[0]) )); } // RTC AddLayer( new OGRTigerLayer( this, new TigerEntityNames( this, papszModules[0]) )); // RTE if (nVersion >= TIGER_2002) { AddLayer( new OGRTigerLayer( this, new TigerPolygonEconomic( this, papszModules[0]) )); } // RTH AddLayer( new OGRTigerLayer( this, new TigerIDHistory( this, papszModules[0]) )); // RTI AddLayer( new OGRTigerLayer( this, new TigerPolyChainLink( this, papszModules[0]) )); // RTM AddLayer( new OGRTigerLayer( this, new TigerSpatialMetadata( this, papszModules[0] ) ) ); // RTP AddLayer( new OGRTigerLayer( this, new TigerPIP( this, papszModules[0]) )); // RTR AddLayer( new OGRTigerLayer( this, new TigerTLIDRange( this, papszModules[0]) )); // RTT if (nVersion >= TIGER_2002) { AddLayer( new OGRTigerLayer( this, new TigerZeroCellID( this, papszModules[0]) )); } // RTU if (nVersion >= TIGER_2002) { AddLayer( new OGRTigerLayer( this, new TigerOverUnder( this, papszModules[0]) )); } // RTZ AddLayer( new OGRTigerLayer( this, new TigerZipPlus4( this, papszModules[0]) )); return TRUE; }
int OGROpenFileGDBDataSource::Open( const char* pszFilename ) { FileGDBTable oTable; m_pszName = CPLStrdup(pszFilename); m_osDirName = pszFilename; int nInterestTable = -1; const char* pszFilenameWithoutPath = CPLGetFilename(pszFilename); if( strlen(pszFilenameWithoutPath) == strlen("a00000000.gdbtable") && pszFilenameWithoutPath[0] == 'a' && sscanf(pszFilenameWithoutPath, "a%08x.gdbtable", &nInterestTable) == 1 ) { m_osDirName = CPLGetPath(m_osDirName); } else { nInterestTable = -1; } if( EQUAL(CPLGetExtension(m_osDirName), "zip") && strncmp(m_osDirName, "/vsizip/", strlen("/vsizip/")) != 0 ) { m_osDirName = "/vsizip/" + m_osDirName; } else if( EQUAL(CPLGetExtension(m_osDirName), "tar") && strncmp(m_osDirName, "/vsitar/", strlen("/vsitar/")) != 0 ) { m_osDirName = "/vsitar/" + m_osDirName; } if( strncmp(m_osDirName, "/vsizip/", strlen("/vsizip/")) == 0 || strncmp(m_osDirName, "/vsitar/", strlen("/vsitar/")) == 0) { /* Look for one subdirectory ending with .gdb extension */ char** papszDir = CPLReadDir(m_osDirName); int iCandidate = -1; for( int i=0; papszDir && papszDir[i] != NULL; i++ ) { VSIStatBufL sStat; if( EQUAL(CPLGetExtension(papszDir[i]), "gdb") && VSIStatL( CPLSPrintf("%s/%s", m_osDirName.c_str(), papszDir[i]), &sStat ) == 0 && VSI_ISDIR(sStat.st_mode) ) { if( iCandidate < 0 ) iCandidate = i; else { iCandidate = -1; break; } } } if( iCandidate >= 0 ) { m_osDirName += "/"; m_osDirName += papszDir[iCandidate]; } CSLDestroy(papszDir); } m_papszFiles = VSIReadDir(m_osDirName); /* Explore catalog table */ const char* psza00000001 = CPLFormFilename(m_osDirName, "a00000001", "gdbtable"); if( !FileExists(psza00000001) || !oTable.Open(psza00000001) ) { if( nInterestTable >= 0 && FileExists(m_pszName) ) { const char* pszLyrName = CPLSPrintf("a%08x", nInterestTable); OGROpenFileGDBLayer* poLayer = new OGROpenFileGDBLayer( m_pszName, pszLyrName, "", ""); const char* pszTablX = CPLResetExtension(m_pszName, "gdbtablx"); if( (!FileExists(pszTablX) && poLayer->GetLayerDefn()->GetFieldCount() == 0 && poLayer->GetFeatureCount() == 0) || !poLayer->IsValidLayerDefn() ) { delete poLayer; return FALSE; } m_apoLayers.push_back(poLayer); return TRUE; } return FALSE; } if( !(oTable.GetFieldCount() >= 2 && oTable.GetField(0)->GetName() == "Name" && oTable.GetField(0)->GetType() == FGFT_STRING && oTable.GetField(1)->GetName() == "FileFormat" && (oTable.GetField(1)->GetType() == FGFT_INT16 || oTable.GetField(1)->GetType() == FGFT_INT32) ) ) { return FALSE; } int iGDBItems = -1; /* V10 */ int iGDBFeatureClasses = -1; /* V9.X */ int iGDBObjectClasses = -1; /* V9.X */ int i; std::vector<std::string> aosTableNames; for(i=0;i<oTable.GetTotalRecordCount();i++) { if( !oTable.SelectRow(i) ) { if( oTable.HasGotError() ) break; aosTableNames.push_back(""); continue; } const OGRField* psField = oTable.GetFieldValue(0); if( psField != NULL ) { aosTableNames.push_back(psField->String); if( strcmp(psField->String, "GDB_Items") == 0 ) { iGDBItems = i; } else if( strcmp(psField->String, "GDB_FeatureClasses") == 0 ) { iGDBFeatureClasses = i; } else if( strcmp(psField->String, "GDB_ObjectClasses") == 0 ) { iGDBObjectClasses = i; } m_osMapNameToIdx[psField->String] = 1 + i; } else { aosTableNames.push_back(""); } } oTable.Close(); if( iGDBItems >= 0 ) { int bRet = OpenFileGDBv10(iGDBItems, nInterestTable); if( !bRet ) return FALSE; } else if( iGDBFeatureClasses >= 0 && iGDBObjectClasses >= 0 ) { int bRet = OpenFileGDBv9(iGDBFeatureClasses, iGDBObjectClasses, nInterestTable); if( !bRet ) return FALSE; } else { CPLError(CE_Failure, CPLE_AppDefined, "No GDB_Items nor GDB_FeatureClasses table"); return FALSE; } if( m_apoLayers.size() == 0 && nInterestTable >= 0 ) { if( FileExists(m_pszName) ) { const char* pszLyrName; if( nInterestTable <= (int)aosTableNames.size() && aosTableNames[nInterestTable-1].size() != 0 ) pszLyrName = aosTableNames[nInterestTable-1].c_str(); else pszLyrName = CPLSPrintf("a%08x", nInterestTable); m_apoLayers.push_back(new OGROpenFileGDBLayer( m_pszName, pszLyrName, "", "")); } else { return FALSE; } } return TRUE; }
// Unix case. static bool TABAdjustCaseSensitiveFilename(char *pszFname) { VSIStatBufL sStatBuf; // First check if the filename is OK as is. if (VSIStatL(pszFname, &sStatBuf) == 0) { return true; } // File either does not exist or has the wrong cases. // Go backwards until we find a portion of the path that is valid. char *pszTmpPath = CPLStrdup(pszFname); const int nTotalLen = static_cast<int>(strlen(pszTmpPath)); int iTmpPtr = nTotalLen; GBool bValidPath = false; while(iTmpPtr > 0 && !bValidPath) { // Move back to the previous '/' separator. pszTmpPath[--iTmpPtr] = '\0'; while( iTmpPtr > 0 && pszTmpPath[iTmpPtr-1] != '/' ) { pszTmpPath[--iTmpPtr] = '\0'; } if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) == 0) bValidPath = true; } CPLAssert(iTmpPtr >= 0); // Assume that CWD is valid. Therefor an empty path is a valid. if (iTmpPtr == 0) bValidPath = true; // Now that we have a valid base, reconstruct the whole path // by scanning all the sub-directories. // If we get to a point where a path component does not exist then // we simply return the rest of the path as is. while(bValidPath && (int)strlen(pszTmpPath) < nTotalLen) { int iLastPartStart = iTmpPtr; char **papszDir = VSIReadDir(pszTmpPath); // Add one component to the current path. pszTmpPath[iTmpPtr] = pszFname[iTmpPtr]; iTmpPtr++; for( ; pszFname[iTmpPtr] != '\0' && pszFname[iTmpPtr]!='/'; iTmpPtr++) { pszTmpPath[iTmpPtr] = pszFname[iTmpPtr]; } while(iLastPartStart < iTmpPtr && pszTmpPath[iLastPartStart] == '/') iLastPartStart++; // And do a case insensitive search in the current dir. for(int iEntry = 0; papszDir && papszDir[iEntry]; iEntry++) { if (EQUAL(pszTmpPath + iLastPartStart, papszDir[iEntry])) { // Fount it. strcpy(pszTmpPath+iLastPartStart, papszDir[iEntry]); break; } } if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) != 0) bValidPath = false; CSLDestroy(papszDir); } // We reached the last valid path component... just copy the rest // of the path as is. if (iTmpPtr < nTotalLen-1) { strncpy(pszTmpPath+iTmpPtr, pszFname+iTmpPtr, nTotalLen-iTmpPtr); } // Update the source buffer and return. strcpy(pszFname, pszTmpPath); CPLFree(pszTmpPath); return bValidPath; }
OGRErr FGdbDriver::CommitTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS) { CPLMutexHolderOptionalLockD(hMutex); bOutHasReopenedDS = FALSE; OGRMutexedDataSource* poMutexedDS = (OGRMutexedDataSource*)poDSInOut; FGdbDataSource* poDS = (FGdbDataSource* )poMutexedDS->GetBaseDataSource(); FGdbDatabaseConnection* pConnection = poDS->GetConnection(); if( !pConnection->IsLocked() ) { CPLError(CE_Failure, CPLE_NotSupported, "No transaction in progress"); return OGRERR_FAILURE; } bOutHasReopenedDS = TRUE; CPLString osName(poMutexedDS->GetName()); CPLString osNameOri(osName); if( osName[osName.size()-1] == '/' || osName[osName.size()-1] == '\\' ) osName.resize(osName.size()-1); #ifndef WIN32 int bPerLayerCopyingForTransaction = poDS->HasPerLayerCopyingForTransaction(); #endif pConnection->m_nRefCount ++; delete poDSInOut; poDSInOut = NULL; poMutexedDS = NULL; poDS = NULL; pConnection->CloseGeodatabase(); CPLString osEditedName(osName); osEditedName += ".ogredited"; #ifndef WIN32 if( bPerLayerCopyingForTransaction ) { int bError = FALSE; char** papszFiles; std::vector<CPLString> aosTmpFilesToClean; // Check for files present in original copy that are not in edited copy // That is to say deleted layers papszFiles = VSIReadDir(osName); for(char** papszIter = papszFiles; !bError && *papszIter; ++papszIter) { if( strcmp(*papszIter, ".") == 0 || strcmp(*papszIter, "..") == 0 ) continue; VSIStatBufL sStat; if( (*papszIter)[0] == 'a' && VSIStatL( CPLFormFilename(osEditedName, *papszIter, NULL), &sStat ) != 0 ) { if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE1") || VSIRename( CPLFormFilename(osName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, "tmp") ) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename %s to %s", CPLFormFilename(osName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, "tmp")); bError = TRUE; } else aosTmpFilesToClean.push_back(CPLFormFilename(osName, *papszIter, "tmp")); } } CSLDestroy(papszFiles); // Move modified files from edited directory to main directory papszFiles = VSIReadDir(osEditedName); for(char** papszIter = papszFiles; !bError && *papszIter; ++papszIter) { if( strcmp(*papszIter, ".") == 0 || strcmp(*papszIter, "..") == 0 ) continue; struct stat sStat; if( lstat( CPLFormFilename(osEditedName, *papszIter, NULL), &sStat ) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot stat %s", CPLFormFilename(osEditedName, *papszIter, NULL)); bError = TRUE; } else if( !S_ISLNK(sStat.st_mode) ) { // If there was such a file in original directory, first rename it // as a temporary file if( lstat( CPLFormFilename(osName, *papszIter, NULL), &sStat ) == 0 ) { if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE2") || VSIRename( CPLFormFilename(osName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, "tmp") ) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename %s to %s", CPLFormFilename(osName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, "tmp")); bError = TRUE; } else aosTmpFilesToClean.push_back(CPLFormFilename(osName, *papszIter, "tmp")); } if( !bError ) { if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE3") || CPLMoveFile( CPLFormFilename(osName, *papszIter, NULL), CPLFormFilename(osEditedName, *papszIter, NULL) ) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot move %s to %s", CPLFormFilename(osEditedName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, NULL)); bError = TRUE; } else CPLDebug("FileGDB", "Move %s to %s", CPLFormFilename(osEditedName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, NULL)); } } } CSLDestroy(papszFiles); if( !bError ) { for(size_t i=0;i<aosTmpFilesToClean.size();i++) { if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE4") || VSIUnlink(aosTmpFilesToClean[i]) != 0 ) { CPLError(CE_Warning, CPLE_AppDefined, "Cannot remove %s. Manual cleanup required", aosTmpFilesToClean[i].c_str()); } } } if( bError ) { CPLError(CE_Failure, CPLE_AppDefined, "An error occurred while moving files from %s back to %s. " "Manual cleaning must be done and dataset should be closed", osEditedName.c_str(), osName.c_str()); pConnection->SetLocked(FALSE); Release(osName); return OGRERR_FAILURE; } else if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE5") || CPLUnlinkTree(osEditedName) != 0 ) { CPLError(CE_Warning, CPLE_AppDefined, "Cannot remove %s. Manual cleanup required", osEditedName.c_str()); } } else #endif { CPLString osTmpName(osName); osTmpName += ".ogrtmp"; /* Install the backup copy as the main database in 3 steps : */ /* first rename the main directory in .tmp */ /* then rename the edited copy under regular name */ /* and finally dispose the .tmp directory */ /* That way there's no risk definitely losing data */ if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE1") || VSIRename(osName, osTmpName) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename %s to %s. Edited database during transaction is in %s" "Dataset should be closed", osName.c_str(), osTmpName.c_str(), osEditedName.c_str()); pConnection->SetLocked(FALSE); Release(osName); return OGRERR_FAILURE; } if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE2") || VSIRename(osEditedName, osName) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot rename %s to %s. The original geodatabase is in '%s'. " "Dataset should be closed", osEditedName.c_str(), osName.c_str(), osTmpName.c_str()); pConnection->SetLocked(FALSE); Release(osName); return OGRERR_FAILURE; } if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE3") || CPLUnlinkTree(osTmpName) != 0 ) { CPLError(CE_Warning, CPLE_AppDefined, "Cannot remove %s. Manual cleanup required", osTmpName.c_str()); } } pConnection->m_pGeodatabase = new Geodatabase; long hr = ::OpenGeodatabase(StringToWString(osName), *(pConnection->m_pGeodatabase)); if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE_REOPEN") || FAILED(hr)) { delete pConnection->m_pGeodatabase; pConnection->m_pGeodatabase = NULL; pConnection->SetLocked(FALSE); Release(osName); GDBErr(hr, "Failed to re-open Geodatabase. Dataset should be closed"); return OGRERR_FAILURE; } FGdbDataSource* pDS = new FGdbDataSource(this, pConnection); pDS->Open(osNameOri, TRUE, NULL); //pDS->SetPerLayerCopyingForTransaction(bPerLayerCopyingForTransaction); poDSInOut = new OGRMutexedDataSource(pDS, TRUE, hMutex, TRUE); pConnection->SetLocked(FALSE); return OGRERR_NONE; }
OGRErr FGdbDriver::StartTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS) { CPLMutexHolderOptionalLockD(hMutex); bOutHasReopenedDS = FALSE; OGRMutexedDataSource* poMutexedDS = (OGRMutexedDataSource*)poDSInOut; FGdbDataSource* poDS = (FGdbDataSource* )poMutexedDS->GetBaseDataSource(); if( !poDS->GetUpdate() ) return OGRERR_FAILURE; FGdbDatabaseConnection* pConnection = poDS->GetConnection(); if( pConnection->GetRefCount() != 1 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot start transaction as database is opened in another connection"); return OGRERR_FAILURE; } if( pConnection->IsLocked() ) { CPLError(CE_Failure, CPLE_AppDefined, "Transaction is already in progress"); return OGRERR_FAILURE; } bOutHasReopenedDS = TRUE; CPLString osName(poMutexedDS->GetName()); CPLString osNameOri(osName); if( osName[osName.size()-1] == '/' || osName[osName.size()-1] == '\\' ) osName.resize(osName.size()-1); #ifndef WIN32 int bPerLayerCopyingForTransaction = poDS->HasPerLayerCopyingForTransaction(); #endif pConnection->m_nRefCount ++; delete poDSInOut; poDSInOut = NULL; poMutexedDS = NULL; poDS = NULL; pConnection->CloseGeodatabase(); CPLString osEditedName(osName); osEditedName += ".ogredited"; CPLPushErrorHandler(CPLQuietErrorHandler); CPL_IGNORE_RET_VAL(CPLUnlinkTree(osEditedName)); CPLPopErrorHandler(); OGRErr eErr = OGRERR_NONE; CPLString osDatabaseToReopen; #ifndef WIN32 if( bPerLayerCopyingForTransaction ) { int bError = FALSE; if( VSIMkdir( osEditedName, 0755 ) != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Cannot create directory '%s'.", osEditedName.c_str() ); bError = TRUE; } // Only copy a0000000X.Y files with X >= 1 && X <= 8, gdb and timestamps // and symlink others char** papszFiles = VSIReadDir(osName); for(char** papszIter = papszFiles; !bError && *papszIter; ++papszIter) { if( strcmp(*papszIter, ".") == 0 || strcmp(*papszIter, "..") == 0 ) continue; if( ((*papszIter)[0] == 'a' && atoi((*papszIter)+1) >= 1 && atoi((*papszIter)+1) <= 8) || EQUAL(*papszIter, "gdb") || EQUAL(*papszIter, "timestamps") ) { if( CPLCopyFile(CPLFormFilename(osEditedName, *papszIter, NULL), CPLFormFilename(osName, *papszIter, NULL)) != 0 ) { bError = TRUE; CPLError(CE_Failure, CPLE_AppDefined, "Cannot copy %s", *papszIter); } } else { CPLString osSourceFile; if( CPLIsFilenameRelative(osName) ) osSourceFile = CPLFormFilename(CPLSPrintf("../%s", CPLGetFilename(osName.c_str())), *papszIter, NULL); else osSourceFile = osName; if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE1") || CPLSymlink( osSourceFile, CPLFormFilename(osEditedName.c_str(), *papszIter, NULL), NULL ) != 0 ) { bError = TRUE; CPLError(CE_Failure, CPLE_AppDefined, "Cannot symlink %s", *papszIter); } } } CSLDestroy(papszFiles); if( bError ) { eErr = OGRERR_FAILURE; osDatabaseToReopen = osName; } else osDatabaseToReopen = osEditedName; } else #endif { if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE1") || CPLCopyTree( osEditedName, osName ) != 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot backup geodatabase"); eErr = OGRERR_FAILURE; osDatabaseToReopen = osName; } else osDatabaseToReopen = osEditedName; } pConnection->m_pGeodatabase = new Geodatabase; long hr = ::OpenGeodatabase(StringToWString(osDatabaseToReopen), *(pConnection->m_pGeodatabase)); if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE2") || FAILED(hr)) { delete pConnection->m_pGeodatabase; pConnection->m_pGeodatabase = NULL; Release(osName); GDBErr(hr, CPLSPrintf("Failed to open %s. Dataset should be closed", osDatabaseToReopen.c_str())); return OGRERR_FAILURE; } FGdbDataSource* pDS = new FGdbDataSource(this, pConnection); pDS->Open(osDatabaseToReopen, TRUE, osNameOri); #ifndef WIN32 if( eErr == OGRERR_NONE && bPerLayerCopyingForTransaction ) { pDS->SetPerLayerCopyingForTransaction(bPerLayerCopyingForTransaction); pDS->SetSymlinkFlagOnAllLayers(); } #endif poDSInOut = new OGRMutexedDataSource(pDS, TRUE, hMutex, TRUE); if( eErr == OGRERR_NONE ) pConnection->SetLocked(TRUE); return eErr; }