diff --git a/apps/gdalwarp_lib.cpp b/apps/gdalwarp_lib.cpp index 7e43acdce3ad..bf4ef59c1d08 100644 --- a/apps/gdalwarp_lib.cpp +++ b/apps/gdalwarp_lib.cpp @@ -1175,8 +1175,8 @@ static bool DealWithCOGOptions(CPLStringList &aosCreateOptions, int nSrcCount, GDALWarpAppOptions oClonedOptions(*psOptions); oClonedOptions.bQuiet = true; - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/gdalwarp/%p.tif", &oClonedOptions); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("gdalwarp_tmp.tif")); CPLStringList aosTmpGTiffCreateOptions; aosTmpGTiffCreateOptions.SetNameValue("SPARSE_OK", "YES"); aosTmpGTiffCreateOptions.SetNameValue("TILED", "YES"); diff --git a/autotest/cpp/test_cpl.cpp b/autotest/cpp/test_cpl.cpp index 710aa876f490..84f182e7e02a 100644 --- a/autotest/cpp/test_cpl.cpp +++ b/autotest/cpp/test_cpl.cpp @@ -5331,4 +5331,194 @@ TEST_F(test_cpl, CPLSpawn) } #endif +static bool ENDS_WITH(const char *pszStr, const char *pszEnd) +{ + return strlen(pszStr) >= strlen(pszEnd) && + strcmp(pszStr + strlen(pszStr) - strlen(pszEnd), pszEnd) == 0; +} + +TEST_F(test_cpl, VSIMemGenerateHiddenFilename) +{ + { + // Initial cleanup + VSIRmdirRecursive("/vsimem/"); + VSIRmdirRecursive("/vsimem/.#!HIDDEN!#."); + + // Generate unlisted filename + const std::string osFilename1 = VSIMemGenerateHiddenFilename(nullptr); + const char *pszFilename1 = osFilename1.c_str(); + EXPECT_TRUE(STARTS_WITH(pszFilename1, "/vsimem/.#!HIDDEN!#./")); + EXPECT_TRUE(ENDS_WITH(pszFilename1, "/unnamed")); + + { + // Check the file doesn't exist yet + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL(pszFilename1, &sStat), -1); + } + + // Create the file with some content + GByte abyDummyData[1] = {0}; + VSIFCloseL(VSIFileFromMemBuffer(pszFilename1, abyDummyData, + sizeof(abyDummyData), false)); + + { + // Check the file exists now + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL(pszFilename1, &sStat), 0); + } + + // Get's back content + EXPECT_EQ(VSIGetMemFileBuffer(pszFilename1, nullptr, false), + abyDummyData); + + { + // Check the hidden file doesn't popup + const CPLStringList aosFiles(VSIReadDir("/vsimem/")); + EXPECT_EQ(aosFiles.size(), 0); + } + + { + // Check that we can list the below directory if we know it exists + // and there's just one subdir + const CPLStringList aosFiles(VSIReadDir("/vsimem/.#!HIDDEN!#.")); + EXPECT_EQ(aosFiles.size(), 1); + } + + { + // but that it is not an explicit directory + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL("/vsimem/.#!HIDDEN!#.", &sStat), -1); + } + + // Creates second file + const std::string osFilename2 = VSIMemGenerateHiddenFilename(nullptr); + const char *pszFilename2 = osFilename2.c_str(); + EXPECT_TRUE(strcmp(pszFilename1, pszFilename2) != 0); + + // Create it + VSIFCloseL(VSIFileFromMemBuffer(pszFilename2, abyDummyData, + sizeof(abyDummyData), false)); + + { + // Check that we can list the root hidden dir if we know it exists + const CPLStringList aosFiles(VSIReadDir("/vsimem/.#!HIDDEN!#.")); + EXPECT_EQ(aosFiles.size(), 2); + } + + { + // Create an explicit subdirectory in a hidden directory + const std::string osBaseName = + VSIMemGenerateHiddenFilename(nullptr); + const std::string osSubDir = + CPLFormFilename(osBaseName.c_str(), "mysubdir", nullptr); + EXPECT_EQ(VSIMkdir(osSubDir.c_str(), 0), 0); + + // Check the subdirectory exists + { + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL(osSubDir.c_str(), &sStat), 0); + } + + // but not its hidden parent + { + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL(osBaseName.c_str(), &sStat), -1); + } + + // Create file within the subdirectory + VSIFCloseL(VSIFileFromMemBuffer( + CPLFormFilename(osSubDir.c_str(), "my.bin", nullptr), + abyDummyData, sizeof(abyDummyData), false)); + + { + // Check that we can list the subdirectory + const CPLStringList aosFiles(VSIReadDir(osSubDir.c_str())); + EXPECT_EQ(aosFiles.size(), 1); + } + + { + // Check that we can list the root hidden dir if we know it exists + const CPLStringList aosFiles( + VSIReadDir("/vsimem/.#!HIDDEN!#.")); + EXPECT_EQ(aosFiles.size(), 3); + } + } + + // Directly create a directory with the return of VSIMemGenerateHiddenFilename() + { + const std::string osDirname = VSIMemGenerateHiddenFilename(nullptr); + EXPECT_EQ(VSIMkdir(osDirname.c_str(), 0), 0); + + // Check the subdirectory exists + { + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL(osDirname.c_str(), &sStat), 0); + } + + // Create file within the subdirectory + VSIFCloseL(VSIFileFromMemBuffer( + CPLFormFilename(osDirname.c_str(), "my.bin", nullptr), + abyDummyData, sizeof(abyDummyData), false)); + + { + // Check there's a file in this subdirectory + const CPLStringList aosFiles(VSIReadDir(osDirname.c_str())); + EXPECT_EQ(aosFiles.size(), 1); + } + + EXPECT_EQ(VSIRmdirRecursive(osDirname.c_str()), 0); + + { + // Check there's no longer any file in this subdirectory + const CPLStringList aosFiles(VSIReadDir(osDirname.c_str())); + EXPECT_EQ(aosFiles.size(), 0); + } + + { + // Check that it no longer exists + VSIStatBufL sStat; + EXPECT_EQ(VSIStatL(osDirname.c_str(), &sStat), -1); + } + } + + // Check that operations on "/vsimem/" do not interfere with hidden files + { + // Create regular file + VSIFCloseL(VSIFileFromMemBuffer("/vsimem/regular_file", + abyDummyData, sizeof(abyDummyData), + false)); + + // Check it is visible + EXPECT_EQ(CPLStringList(VSIReadDir("/vsimem/")).size(), 1); + + // Clean root /vsimem/ + VSIRmdirRecursive("/vsimem/"); + + // No more user files + EXPECT_TRUE(CPLStringList(VSIReadDir("/vsimem/")).empty()); + + // But still hidden files + EXPECT_TRUE( + !CPLStringList(VSIReadDir("/vsimem/.#!HIDDEN!#.")).empty()); + } + + // Clean-up hidden files + EXPECT_EQ(VSIRmdirRecursive("/vsimem/.#!HIDDEN!#."), 0); + + { + // Check the root hidden dir is empty + const CPLStringList aosFiles(VSIReadDir("/vsimem/.#!HIDDEN!#.")); + EXPECT_TRUE(aosFiles.empty()); + } + + EXPECT_EQ(VSIRmdirRecursive("/vsimem/.#!HIDDEN!#."), 0); + } + + { + const std::string osFilename = VSIMemGenerateHiddenFilename("foo.bar"); + const char *pszFilename = osFilename.c_str(); + EXPECT_TRUE(STARTS_WITH(pszFilename, "/vsimem/.#!HIDDEN!#./")); + EXPECT_TRUE(ENDS_WITH(pszFilename, "/foo.bar")); + } +} } // namespace diff --git a/autotest/gcore/vsifile.py b/autotest/gcore/vsifile.py index 57b359a35661..4b648807a813 100755 --- a/autotest/gcore/vsifile.py +++ b/autotest/gcore/vsifile.py @@ -150,6 +150,26 @@ def vsifile_generic(filename, options=[]): gdal.Unlink(filename) + if not filename.startswith("/vsicrypt/"): + assert gdal.RmdirRecursive(filename + "/i_dont_exist") == -1 + + subdir = filename + "/subdir" + assert gdal.MkdirRecursive(subdir + "/subsubdir", 0o755) == 0 + + assert gdal.VSIStatL(subdir) is not None + assert gdal.VSIStatL(subdir + "/subsubdir") is not None + + if not filename.startswith("/vsimem/"): + assert gdal.Rmdir(subdir) == -1 + assert gdal.VSIStatL(subdir) is not None + + # Safety belt... + assert filename.startswith("tmp/") or filename.startswith("/vsimem/") + assert gdal.RmdirRecursive(filename) == 0 + + assert gdal.VSIStatL(subdir) is None + assert gdal.VSIStatL(subdir + "/subsubdir") is None + ############################################################################### # Test /vsimem diff --git a/autotest/gdrivers/jp2openjpeg.py b/autotest/gdrivers/jp2openjpeg.py index 46820ee810e7..cc64df8dabf1 100755 --- a/autotest/gdrivers/jp2openjpeg.py +++ b/autotest/gdrivers/jp2openjpeg.py @@ -2744,10 +2744,10 @@ def test_jp2openjpeg_45(): ) del out_ds - dircontent = gdal.ReadDir("/vsimem/") + dircontent = gdal.ReadDir("/vsimem/.#!HIDDEN!#.") if dircontent: for filename in dircontent: - assert not filename.startswith("gmljp2") + assert "gmljp2" not in filename ds = ogr.Open("/vsimem/jp2openjpeg_45.jp2") assert ds.GetLayerCount() == 1 diff --git a/autotest/ogr/ogr_csw.py b/autotest/ogr/ogr_csw.py index 653de9c73981..b6fb800d4688 100755 --- a/autotest/ogr/ogr_csw.py +++ b/autotest/ogr/ogr_csw.py @@ -46,9 +46,14 @@ def module_disable_exceptions(): ############################################################################### @pytest.fixture(autouse=True, scope="module") def setup_and_cleanup(): + + vsimem_hidden_before = gdal.ReadDirRecursive("/vsimem/.#!HIDDEN!#.") + with gdal.config_option("CPL_CURL_ENABLE_VSIMEM", "YES"): yield + assert gdal.ReadDirRecursive("/vsimem/.#!HIDDEN!#.") == vsimem_hidden_before + ############################################################################### # Test underlying OGR drivers diff --git a/autotest/ogr/ogr_wfs.py b/autotest/ogr/ogr_wfs.py index 7873234f9d2a..3fe3b91695ed 100755 --- a/autotest/ogr/ogr_wfs.py +++ b/autotest/ogr/ogr_wfs.py @@ -63,9 +63,13 @@ def ogr_wfs_init(): if gml_ds is None: pytest.skip("cannot read GML files") + vsimem_hidden_before = gdal.ReadDirRecursive("/vsimem/.#!HIDDEN!#.") + with gdal.config_option("CPL_CURL_ENABLE_VSIMEM", "YES"): yield + assert gdal.ReadDirRecursive("/vsimem/.#!HIDDEN!#.") == vsimem_hidden_before + @pytest.fixture( params=["NO", None], scope="module", ids=["without-streaming", "with-streaming"] diff --git a/frmts/cals/calsdataset.cpp b/frmts/cals/calsdataset.cpp index f8267075379f..389308524764 100644 --- a/frmts/cals/calsdataset.cpp +++ b/frmts/cals/calsdataset.cpp @@ -331,7 +331,7 @@ GDALDataset *CALSDataset::Open(GDALOpenInfo *poOpenInfo) // Create a TIFF header for a single-strip CCITTFAX4 file. poDS->osTIFFHeaderFilename = - CPLSPrintf("/vsimem/cals/header_%p.tiff", poDS); + VSIMemGenerateHiddenFilename("cals_header.tiff"); VSILFILE *fp = VSIFOpenL(poDS->osTIFFHeaderFilename, "wb"); const int nTagCount = 10; const int nHeaderSize = 4 + 4 + 2 + nTagCount * 12 + 4; @@ -359,7 +359,7 @@ GDALDataset *CALSDataset::Open(GDALOpenInfo *poOpenInfo) // Create a /vsisparse/ description file assembling the TIFF header // with the FAX4 codestream that starts at offset 2048 of the CALS file. - poDS->osSparseFilename = CPLSPrintf("/vsimem/cals/sparse_%p.xml", poDS); + poDS->osSparseFilename = VSIMemGenerateHiddenFilename("cals_sparse.xml"); fp = VSIFOpenL(poDS->osSparseFilename, "wb"); CPLAssert(fp); VSIFPrintfL(fp, @@ -473,7 +473,8 @@ GDALDataset *CALSDataset::CreateCopy(const char *pszFilename, // Write a in-memory TIFF with just the TIFF header to figure out // how large it will be. - CPLString osTmpFilename(CPLSPrintf("/vsimem/cals/tmp_%p", poSrcDS)); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("tmp_tif_header")); char **papszOptions = nullptr; papszOptions = CSLSetNameValue(papszOptions, "COMPRESS", "CCITTFAX4"); papszOptions = CSLSetNameValue(papszOptions, "NBITS", "1"); diff --git a/frmts/daas/daasdataset.cpp b/frmts/daas/daasdataset.cpp index 0c68c9e31439..8672c941a699 100644 --- a/frmts/daas/daasdataset.cpp +++ b/frmts/daas/daasdataset.cpp @@ -2420,7 +2420,7 @@ CPLErr GDALDAASRasterBand::GetBlocks(int nBlockXOff, int nBlockYOff, } else { - CPLString osTmpMemFile = CPLSPrintf("/vsimem/daas_%p", this); + const CPLString osTmpMemFile = VSIMemGenerateHiddenFilename("daas"); VSIFCloseL(VSIFileFromMemBuffer( osTmpMemFile, psResult->pasMimePart[iDataPart].pabyData, psResult->pasMimePart[iDataPart].nDataLen, false)); diff --git a/frmts/ecw/ecwdataset.cpp b/frmts/ecw/ecwdataset.cpp index dd7bde5a9b1a..6c94add614c1 100644 --- a/frmts/ecw/ecwdataset.cpp +++ b/frmts/ecw/ecwdataset.cpp @@ -2850,10 +2850,11 @@ GDALDataset *ECWDataset::Open(GDALOpenInfo *poOpenInfo, int bIsJPEG2000) /* There are issues at least in the 5.x series. */ /* -------------------------------------------------------------------- */ #if ECWSDK_VERSION >= 40 + constexpr const char *szDETECT_BUG_FILENAME = + "__detect_ecw_uint32_bug__.j2k"; if (bIsJPEG2000 && poDS->eNCSRequestDataType == NCSCT_UINT32 && CPLTestBool(CPLGetConfigOption("ECW_CHECK_CORRECT_DECODING", "TRUE")) && - !STARTS_WITH_CI(poOpenInfo->pszFilename, - "/vsimem/detect_ecw_uint32_bug")) + strstr(poOpenInfo->pszFilename, szDETECT_BUG_FILENAME) == nullptr) { static bool bUINT32_Ok = false; { @@ -2878,7 +2879,7 @@ GDALDataset *ECWDataset::Open(GDALOpenInfo *poOpenInfo, int bIsJPEG2000) 0xDF, 0xFF, 0x7F, 0x5F, 0xFF, 0xD9}; const std::string osTmpFilename = - CPLSPrintf("/vsimem/detect_ecw_uint32_bug_%p.j2k", poDS); + VSIMemGenerateHiddenFilename(szDETECT_BUG_FILENAME); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), const_cast(abyTestUInt32ImageData), diff --git a/frmts/eeda/eedaidataset.cpp b/frmts/eeda/eedaidataset.cpp index 9a6c41be78b8..e6df9d0d2a8a 100644 --- a/frmts/eeda/eedaidataset.cpp +++ b/frmts/eeda/eedaidataset.cpp @@ -433,7 +433,7 @@ bool GDALEEDAIRasterBand::DecodeGDALDataset(const GByte *pabyData, int nDataLen, { GDALEEDAIDataset *poGDS = reinterpret_cast(poDS); - CPLString osTmpFilename(CPLSPrintf("/vsimem/eeai/%p", this)); + const CPLString osTmpFilename(VSIMemGenerateHiddenFilename("eedai")); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename, const_cast(pabyData), nDataLen, false)); const char *const apszDrivers[] = {"PNG", "JPEG", "GTIFF", nullptr}; diff --git a/frmts/esric/esric_dataset.cpp b/frmts/esric/esric_dataset.cpp index 7ff5fdd585f4..2d5768762b59 100644 --- a/frmts/esric/esric_dataset.cpp +++ b/frmts/esric/esric_dataset.cpp @@ -896,9 +896,7 @@ CPLErr ECBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) GUInt64(size), GUInt64(offset)); return CE_Failure; } - CPLString magic; - // Should use some sort of unique - magic.Printf("/vsimem/esric_%p.tmp", this); + const CPLString magic(VSIMemGenerateHiddenFilename("esric.tmp")); auto mfh = VSIFileFromMemBuffer(magic.c_str(), fbuffer.data(), size, false); VSIFCloseL(mfh); // Can't open a raster by handle? diff --git a/frmts/georaster/georaster_wrapper.cpp b/frmts/georaster/georaster_wrapper.cpp index cdb9dbd8c9cb..7114592c1131 100644 --- a/frmts/georaster/georaster_wrapper.cpp +++ b/frmts/georaster/georaster_wrapper.cpp @@ -4236,13 +4236,13 @@ void GeoRasterWrapper::UncompressJpeg(unsigned long nInSize) // Load JPEG in a virtual file // -------------------------------------------------------------------- - const char *pszMemFile = CPLSPrintf("/vsimem/geor_%p.jpg", pabyBlockBuf); + const CPLString osMemFile = VSIMemGenerateHiddenFilename("geor.jpg"); - VSILFILE *fpImage = VSIFOpenL(pszMemFile, "wb"); + VSILFILE *fpImage = VSIFOpenL(osMemFile, "wb"); VSIFWriteL(pabyBlockBuf, nInSize, 1, fpImage); VSIFCloseL(fpImage); - fpImage = VSIFOpenL(pszMemFile, "rb"); + fpImage = VSIFOpenL(osMemFile, "rb"); // -------------------------------------------------------------------- // Initialize decompressor @@ -4299,7 +4299,7 @@ void GeoRasterWrapper::UncompressJpeg(unsigned long nInSize) VSIFCloseL(fpImage); - VSIUnlink(pszMemFile); + VSIUnlink(osMemFile); } // --------------------------------------------------------------------------- @@ -4312,9 +4312,9 @@ unsigned long GeoRasterWrapper::CompressJpeg(void) // Load JPEG in a virtual file // -------------------------------------------------------------------- - const char *pszMemFile = CPLSPrintf("/vsimem/geor_%p.jpg", pabyBlockBuf); + const CPLString osMemFile = VSIMemGenerateHiddenFilename("geor.jpg"); - VSILFILE *fpImage = VSIFOpenL(pszMemFile, "wb"); + VSILFILE *fpImage = VSIFOpenL(osMemFile, "wb"); bool write_all_tables = TRUE; @@ -4389,11 +4389,11 @@ unsigned long GeoRasterWrapper::CompressJpeg(void) VSIFCloseL(fpImage); - fpImage = VSIFOpenL(pszMemFile, "rb"); + fpImage = VSIFOpenL(osMemFile, "rb"); size_t nSize = VSIFReadL(pabyCompressBuf, 1, nBlockBytes, fpImage); VSIFCloseL(fpImage); - VSIUnlink(pszMemFile); + VSIUnlink(osMemFile); return (unsigned long)nSize; } diff --git a/frmts/grib/degrib/g2clib/dec_jpeg2000.cpp b/frmts/grib/degrib/g2clib/dec_jpeg2000.cpp index a22109e823f8..cf0961c637e8 100644 --- a/frmts/grib/degrib/g2clib/dec_jpeg2000.cpp +++ b/frmts/grib/degrib/g2clib/dec_jpeg2000.cpp @@ -52,8 +52,8 @@ int dec_jpeg2000(const void *injpc,g2int bufsize,g2int **outfld,g2int outpixels) { // create "memory file" from buffer - CPLString osFileName; - osFileName.Printf( "/vsimem/work_grib_%p.jpc", injpc ); + const CPLString osFileName( + VSIMemGenerateHiddenFilename("temp_grib.jpc")); VSIFCloseL( VSIFileFromMemBuffer( osFileName, (unsigned char*)injpc, bufsize, diff --git a/frmts/grib/gribcreatecopy.cpp b/frmts/grib/gribcreatecopy.cpp index 6a886d410656..6a9637bca749 100644 --- a/frmts/grib/gribcreatecopy.cpp +++ b/frmts/grib/gribcreatecopy.cpp @@ -1664,7 +1664,7 @@ bool GRIB2Section567Writer::WritePNG() GDALDataset *poMEMDS = WrapArrayAsMemDataset(m_nXSize, m_nYSize, eReducedDT, panData); - CPLString osTmpFile(CPLSPrintf("/vsimem/grib_driver_%p.png", m_poSrcDS)); + const CPLString osTmpFile(VSIMemGenerateHiddenFilename("grib_driver.png")); GDALDataset *poPNGDS = poPNGDriver->CreateCopy( osTmpFile, poMEMDS, FALSE, aosPNGOptions.List(), nullptr, nullptr); if (poPNGDS == nullptr) @@ -1850,7 +1850,7 @@ bool GRIB2Section567Writer::WriteJPEG2000(char **papszOptions) GDALDataset *poMEMDS = WrapArrayAsMemDataset(m_nXSize, m_nYSize, eReducedDT, panData); - CPLString osTmpFile(CPLSPrintf("/vsimem/grib_driver_%p.j2k", m_poSrcDS)); + const CPLString osTmpFile(VSIMemGenerateHiddenFilename("grib_driver.j2k")); GDALDataset *poJ2KDS = poJ2KDriver->CreateCopy( osTmpFile, poMEMDS, FALSE, aosJ2KOptions.List(), nullptr, nullptr); if (poJ2KDS == nullptr) diff --git a/frmts/grib/gribdataset.cpp b/frmts/grib/gribdataset.cpp index f098463b23c6..c7a42e496819 100644 --- a/frmts/grib/gribdataset.cpp +++ b/frmts/grib/gribdataset.cpp @@ -1489,10 +1489,7 @@ GDALDataset *GRIBDataset::Open(GDALOpenInfo *poOpenInfo) // for other thread safe formats CPLMutexHolderD(&hGRIBMutex); - CPLString tmpFilename; - tmpFilename.Printf("/vsimem/gribdataset-%p", poOpenInfo); - - VSILFILE *memfp = VSIFileFromMemBuffer(tmpFilename, poOpenInfo->pabyHeader, + VSILFILE *memfp = VSIFileFromMemBuffer(nullptr, poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes, FALSE); if (memfp == nullptr || ReadSECT0(memfp, &buff, &buffLen, -1, sect0, &gribLen, &version) < 0) @@ -1500,7 +1497,6 @@ GDALDataset *GRIBDataset::Open(GDALOpenInfo *poOpenInfo) if (memfp != nullptr) { VSIFCloseL(memfp); - VSIUnlink(tmpFilename); } free(buff); char *errMsg = errSprintf(nullptr); @@ -1510,7 +1506,6 @@ GDALDataset *GRIBDataset::Open(GDALOpenInfo *poOpenInfo) return nullptr; } VSIFCloseL(memfp); - VSIUnlink(tmpFilename); free(buff); // Confirm the requested access is supported. diff --git a/frmts/gtiff/geotiff.cpp b/frmts/gtiff/geotiff.cpp index 55b1d9ebf6f9..77b6c0ee6b88 100644 --- a/frmts/gtiff/geotiff.cpp +++ b/frmts/gtiff/geotiff.cpp @@ -701,8 +701,8 @@ void GTiffWriteJPEGTables(TIFF *hTIFF, const char *pszPhotometric, if (!TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(l_nBitsPerSample))) l_nBitsPerSample = 1; - CPLString osTmpFilenameIn; - osTmpFilenameIn.Printf("%s%p", szJPEGGTiffDatasetTmpPrefix, hTIFF); + const CPLString osTmpFilenameIn( + VSIMemGenerateHiddenFilename("gtiffdataset_jpg_tmp")); VSILFILE *fpTmp = nullptr; CPLString osTmp; char **papszLocalParameters = nullptr; @@ -723,6 +723,8 @@ void GTiffWriteJPEGTables(TIFF *hTIFF, const char *pszPhotometric, CPLSPrintf("%u", l_nBitsPerSample)); papszLocalParameters = CSLSetNameValue(papszLocalParameters, "JPEGTABLESMODE", pszJPEGTablesMode); + papszLocalParameters = + CSLSetNameValue(papszLocalParameters, "WRITE_JPEGTABLE_TAG", "NO"); TIFF *hTIFFTmp = GTiffDataset::CreateLL(osTmpFilenameIn, nInMemImageWidth, diff --git a/frmts/gtiff/gt_jpeg_copy.cpp b/frmts/gtiff/gt_jpeg_copy.cpp index 73262092f210..2a647ff190fb 100644 --- a/frmts/gtiff/gt_jpeg_copy.cpp +++ b/frmts/gtiff/gt_jpeg_copy.cpp @@ -377,13 +377,10 @@ static void GTIFF_ErrorExitJPEG(j_common_ptr cinfo) /************************************************************************/ static void GTIFF_Set_TIFFTAG_JPEGTABLES(TIFF *hTIFF, - jpeg_decompress_struct &sDInfo, jpeg_compress_struct &sCInfo) { - char szTmpFilename[128] = {'\0'}; - snprintf(szTmpFilename, sizeof(szTmpFilename), "/vsimem/tables_%p", - &sDInfo); - VSILFILE *fpTABLES = VSIFOpenL(szTmpFilename, "wb+"); + const std::string osTmpFilename(VSIMemGenerateHiddenFilename("tables")); + VSILFILE *fpTABLES = VSIFOpenL(osTmpFilename.c_str(), "wb+"); uint16_t nPhotometric = 0; TIFFGetField(hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric); @@ -409,11 +406,11 @@ static void GTIFF_Set_TIFFTAG_JPEGTABLES(TIFF *hTIFF, vsi_l_offset nSizeTables = 0; GByte *pabyJPEGTablesData = - VSIGetMemFileBuffer(szTmpFilename, &nSizeTables, FALSE); + VSIGetMemFileBuffer(osTmpFilename.c_str(), &nSizeTables, FALSE); TIFFSetField(hTIFF, TIFFTAG_JPEGTABLES, static_cast(nSizeTables), pabyJPEGTablesData); - VSIUnlink(szTmpFilename); + VSIUnlink(osTmpFilename.c_str()); } /************************************************************************/ @@ -476,7 +473,7 @@ CPLErr GTIFF_CopyFromJPEG_WriteAdditionalTags(TIFF *hTIFF, GDALDataset *poSrcDS) jpeg_CreateCompress(&sCInfo, JPEG_LIB_VERSION, sizeof(sCInfo)); bCallDestroyCompress = true; jpeg_copy_critical_parameters(&sDInfo, &sCInfo); - GTIFF_Set_TIFFTAG_JPEGTABLES(hTIFF, sDInfo, sCInfo); + GTIFF_Set_TIFFTAG_JPEGTABLES(hTIFF, sCInfo); bCallDestroyCompress = false; jpeg_abort_compress(&sCInfo); jpeg_destroy_compress(&sCInfo); @@ -578,8 +575,9 @@ typedef struct static CPLErr GTIFF_CopyBlockFromJPEG(GTIFF_CopyBlockFromJPEGArgs *psArgs) { - CPLString osTmpFilename(CPLSPrintf("/vsimem/%p", psArgs->psDInfo)); - VSILFILE *fpMEM = VSIFOpenL(osTmpFilename, "wb+"); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("GTIFF_CopyBlockFromJPEG.tif")); + VSILFILE *fpMEM = VSIFOpenL(osTmpFilename.c_str(), "wb+"); /* -------------------------------------------------------------------- */ /* Initialization of the compressor */ @@ -588,7 +586,7 @@ static CPLErr GTIFF_CopyBlockFromJPEG(GTIFF_CopyBlockFromJPEGArgs *psArgs) if (setjmp(setjmp_buffer)) { CPL_IGNORE_RET_VAL(VSIFCloseL(fpMEM)); - VSIUnlink(osTmpFilename); + VSIUnlink(osTmpFilename.c_str()); return CE_Failure; } @@ -775,7 +773,8 @@ static CPLErr GTIFF_CopyBlockFromJPEG(GTIFF_CopyBlockFromJPEGArgs *psArgs) /* Write the JPEG content with libtiff raw API */ /* -------------------------------------------------------------------- */ vsi_l_offset nSize = 0; - GByte *pabyJPEGData = VSIGetMemFileBuffer(osTmpFilename, &nSize, FALSE); + GByte *pabyJPEGData = + VSIGetMemFileBuffer(osTmpFilename.c_str(), &nSize, FALSE); CPLErr eErr = CE_None; @@ -794,7 +793,7 @@ static CPLErr GTIFF_CopyBlockFromJPEG(GTIFF_CopyBlockFromJPEGArgs *psArgs) eErr = CE_Failure; } - VSIUnlink(osTmpFilename); + VSIUnlink(osTmpFilename.c_str()); return eErr; } diff --git a/frmts/gtiff/gt_wkt_srs.cpp b/frmts/gtiff/gt_wkt_srs.cpp index 919829f2d511..1bffb47d8f1d 100644 --- a/frmts/gtiff/gt_wkt_srs.cpp +++ b/frmts/gtiff/gt_wkt_srs.cpp @@ -42,7 +42,6 @@ #include "cpl_conv.h" #include "cpl_error.h" -#include "cpl_multiproc.h" #include "cpl_string.h" #include "cpl_vsi.h" #include "gt_citation.h" @@ -3513,10 +3512,8 @@ CPLErr GTIFWktFromMemBufEx(int nSize, unsigned char *pabyBuffer, char ***ppapszRPCMD) { - char szFilename[100] = {}; - - snprintf(szFilename, sizeof(szFilename), "/vsimem/wkt_from_mem_buf_%ld.tif", - static_cast(CPLGetPID())); + const std::string osFilename( + VSIMemGenerateHiddenFilename("wkt_from_mem_buf.tif")); /* -------------------------------------------------------------------- */ /* Initialization of libtiff and libgeotiff. */ @@ -3527,20 +3524,21 @@ CPLErr GTIFWktFromMemBufEx(int nSize, unsigned char *pabyBuffer, /* -------------------------------------------------------------------- */ /* Create a memory file from the buffer. */ /* -------------------------------------------------------------------- */ - VSILFILE *fp = VSIFileFromMemBuffer(szFilename, pabyBuffer, nSize, FALSE); + VSILFILE *fp = + VSIFileFromMemBuffer(osFilename.c_str(), pabyBuffer, nSize, FALSE); if (fp == nullptr) return CE_Failure; /* -------------------------------------------------------------------- */ /* Initialize access to the memory geotiff structure. */ /* -------------------------------------------------------------------- */ - TIFF *hTIFF = VSI_TIFFOpen(szFilename, "rc", fp); + TIFF *hTIFF = VSI_TIFFOpen(osFilename.c_str(), "rc", fp); if (hTIFF == nullptr) { CPLError(CE_Failure, CPLE_AppDefined, "TIFF/GeoTIFF structure is corrupt."); - VSIUnlink(szFilename); + VSIUnlink(osFilename.c_str()); CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); return CE_Failure; } @@ -3678,7 +3676,7 @@ CPLErr GTIFWktFromMemBufEx(int nSize, unsigned char *pabyBuffer, XTIFFClose(hTIFF); CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - VSIUnlink(szFilename); + VSIUnlink(osFilename.c_str()); if (phSRS && *phSRS == nullptr) return CE_Failure; @@ -3709,10 +3707,8 @@ CPLErr GTIFMemBufFromSRS(OGRSpatialReferenceH hSRS, char **papszRPCMD) { - char szFilename[100] = {}; - - snprintf(szFilename, sizeof(szFilename), "/vsimem/wkt_from_mem_buf_%ld.tif", - static_cast(CPLGetPID())); + const std::string osFilename( + VSIMemGenerateHiddenFilename("wkt_from_mem_buf.tif")); /* -------------------------------------------------------------------- */ /* Initialization of libtiff and libgeotiff. */ @@ -3723,17 +3719,18 @@ CPLErr GTIFMemBufFromSRS(OGRSpatialReferenceH hSRS, /* -------------------------------------------------------------------- */ /* Initialize access to the memory geotiff structure. */ /* -------------------------------------------------------------------- */ - VSILFILE *fpL = VSIFOpenL(szFilename, "w"); + VSILFILE *fpL = VSIFOpenL(osFilename.c_str(), "w"); if (fpL == nullptr) return CE_Failure; - TIFF *hTIFF = VSI_TIFFOpen(szFilename, "w", fpL); + TIFF *hTIFF = VSI_TIFFOpen(osFilename.c_str(), "w", fpL); if (hTIFF == nullptr) { CPLError(CE_Failure, CPLE_AppDefined, "TIFF/GeoTIFF structure is corrupt."); CPL_IGNORE_RET_VAL(VSIFCloseL(fpL)); + VSIUnlink(osFilename.c_str()); return CE_Failure; } @@ -3885,7 +3882,7 @@ CPLErr GTIFMemBufFromSRS(OGRSpatialReferenceH hSRS, /* -------------------------------------------------------------------- */ GUIntBig nBigLength = 0; - *ppabyBuffer = VSIGetMemFileBuffer(szFilename, &nBigLength, TRUE); + *ppabyBuffer = VSIGetMemFileBuffer(osFilename.c_str(), &nBigLength, TRUE); *pnSize = static_cast(nBigLength); return CE_None; diff --git a/frmts/gtiff/gtiffdataset.h b/frmts/gtiff/gtiffdataset.h index 2c54e910a31e..ab8af5725f8d 100644 --- a/frmts/gtiff/gtiffdataset.h +++ b/frmts/gtiff/gtiffdataset.h @@ -54,9 +54,6 @@ enum class GTiffProfile : GByte // This must be a #define, since it is used in a XSTRINGIFY() macro #define DEFAULT_WEBP_LEVEL 75 -constexpr const char *const szJPEGGTiffDatasetTmpPrefix = - "/vsimem/gtiffdataset_jpg_tmp_"; - class GTiffBitmapBand; class GTiffDataset; class GTiffJPEGOverviewBand; diff --git a/frmts/gtiff/gtiffdataset_read.cpp b/frmts/gtiff/gtiffdataset_read.cpp index 2cdcdbeada92..7b8d3e24b374 100644 --- a/frmts/gtiff/gtiffdataset_read.cpp +++ b/frmts/gtiff/gtiffdataset_read.cpp @@ -704,8 +704,8 @@ static void CPL_STDCALL ThreadDecompressionFuncErrorHandler( { // Generate a dummy in-memory TIFF file that has all the needed tags // from the original file - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/decompress_%p.tif", psJob); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("decompress.tif")); VSILFILE *fpTmp = VSIFOpenL(osTmpFilename.c_str(), "wb+"); TIFF *hTIFFTmp = VSI_TIFFOpen(osTmpFilename.c_str(), @@ -3524,9 +3524,8 @@ static bool GTIFFExtendMemoryFile(const CPLString &osTmpFilename, static bool GTIFFMakeBufferedStream(GDALOpenInfo *poOpenInfo) { - CPLString osTmpFilename; - static int nCounter = 0; - osTmpFilename.Printf("/vsimem/stream_%d.tif", ++nCounter); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("GTIFFMakeBufferedStream.tif")); VSILFILE *fpTemp = VSIFOpenL(osTmpFilename, "wb+"); if (fpTemp == nullptr) return false; diff --git a/frmts/gtiff/gtiffdataset_write.cpp b/frmts/gtiff/gtiffdataset_write.cpp index 4146fcc84236..1ce0ea1c68d0 100644 --- a/frmts/gtiff/gtiffdataset_write.cpp +++ b/frmts/gtiff/gtiffdataset_write.cpp @@ -947,8 +947,8 @@ void GTiffDataset::InitCompressionThreads(bool bUpdateMode, i < static_cast(m_asCompressionJobs.size()); ++i) { m_asCompressionJobs[i].pszTmpFilename = - CPLStrdup(CPLSPrintf("/vsimem/gtiff/thread/job/%p", - &m_asCompressionJobs[i])); + CPLStrdup(VSIMemGenerateHiddenFilename( + CPLSPrintf("thread_job_%d.tif", i))); m_asCompressionJobs[i].nStripOrTile = -1; } @@ -1383,7 +1383,7 @@ bool GTiffDataset::SubmitCompressionJob(int nStripOrTile, GByte *pabyData, memset(&sJob, 0, sizeof(sJob)); SetupJob(sJob); sJob.pszTmpFilename = - CPLStrdup(CPLSPrintf("/vsimem/gtiff/%p", this)); + CPLStrdup(VSIMemGenerateHiddenFilename("temp.tif")); ThreadCompressionFunc(&sJob); @@ -5344,8 +5344,7 @@ TIFF *GTiffDataset::CreateLL(const char *pszFilename, int nXSize, int nYSize, } if (bStreaming) { - static int nCounter = 0; - l_osTmpFilename = CPLSPrintf("/vsimem/vsistdout_%d.tif", ++nCounter); + l_osTmpFilename = VSIMemGenerateHiddenFilename("vsistdout.tif"); pszFilename = l_osTmpFilename.c_str(); } @@ -5875,7 +5874,6 @@ TIFF *GTiffDataset::CreateLL(const char *pszFilename, int nXSize, int nYSize, // strip/tile writing, which is too late, since we have already crystalized // the directory. This way we avoid a directory rewriting. if (l_nCompression == COMPRESSION_JPEG && - !STARTS_WITH(pszFilename, szJPEGGTiffDatasetTmpPrefix) && CPLTestBool( CSLFetchNameValueDef(papszParamList, "WRITE_JPEGTABLE_TAG", "YES"))) { @@ -6068,9 +6066,8 @@ int GTiffDataset::GuessJPEGQuality(bool &bOutHasQuantizationTable, papszLocalParameters = CSLSetNameValue(papszLocalParameters, "NBITS", "12"); - CPLString osTmpFilenameIn; - osTmpFilenameIn.Printf("/vsimem/gtiffdataset_guess_jpeg_quality_tmp_%p", - this); + const CPLString osTmpFilenameIn( + VSIMemGenerateHiddenFilename("gtiffdataset_guess_jpeg_quality_tmp")); int nRet = -1; for (int nQuality = 0; nQuality <= 100 && nRet < 0; ++nQuality) diff --git a/frmts/gtiff/gtiffjpegoverviewds.cpp b/frmts/gtiff/gtiffjpegoverviewds.cpp index cc3ca61e3db6..86e4205107e0 100644 --- a/frmts/gtiff/gtiffjpegoverviewds.cpp +++ b/frmts/gtiff/gtiffjpegoverviewds.cpp @@ -71,7 +71,7 @@ GTiffJPEGOverviewDS::GTiffJPEGOverviewDS(GTiffDataset *poParentDSIn, { ShareLockWithParentDataset(poParentDSIn); - m_osTmpFilenameJPEGTable.Printf("/vsimem/jpegtable_%p", this); + m_osTmpFilenameJPEGTable = VSIMemGenerateHiddenFilename("jpegtable"); const GByte abyAdobeAPP14RGB[] = {0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, @@ -221,7 +221,7 @@ CPLErr GTiffJPEGOverviewBand::IReadBlock(int nBlockXOff, int nBlockYOff, nByteCount -= 2; CPLString osFileToOpen; - m_poGDS->m_osTmpFilename.Printf("/vsimem/sparse_%p", m_poGDS); + m_poGDS->m_osTmpFilename = VSIMemGenerateHiddenFilename("sparse"); VSILFILE *fp = VSIFOpenL(m_poGDS->m_osTmpFilename, "wb+"); // If the size of the JPEG strip/tile is small enough, we will diff --git a/frmts/heif/heifdataset.cpp b/frmts/heif/heifdataset.cpp index 8fff6737fe9a..86e00c177b9b 100644 --- a/frmts/heif/heifdataset.cpp +++ b/frmts/heif/heifdataset.cpp @@ -392,8 +392,8 @@ void GDALHEIFDataset::ReadMetadata() } } - CPLString osTempFile; - osTempFile.Printf("/vsimem/heif_exif_%p.tif", this); + const CPLString osTempFile( + VSIMemGenerateHiddenFilename("heif_exif.tif")); VSILFILE *fpTemp = VSIFileFromMemBuffer(osTempFile, &data[nTIFFFileOffset], nCount - nTIFFFileOffset, FALSE); diff --git a/frmts/http/httpdriver.cpp b/frmts/http/httpdriver.cpp index 1c17d82eb5d1..153a4863b6c5 100644 --- a/frmts/http/httpdriver.cpp +++ b/frmts/http/httpdriver.cpp @@ -29,7 +29,6 @@ #include "cpl_string.h" #include "cpl_http.h" -#include "cpl_atomic_ops.h" #include "gdal_frmts.h" #include "gdal_pam.h" @@ -87,8 +86,6 @@ static std::string HTTPFetchContentDispositionFilename(char **papszHeaders) static GDALDataset *HTTPOpen(GDALOpenInfo *poOpenInfo) { - static volatile int nCounter = 0; - if (poOpenInfo->nHeaderBytes != 0) return nullptr; @@ -116,10 +113,6 @@ static GDALDataset *HTTPOpen(GDALOpenInfo *poOpenInfo) /* -------------------------------------------------------------------- */ /* Create a memory file from the result. */ /* -------------------------------------------------------------------- */ - CPLString osResultFilename; - - int nNewCounter = CPLAtomicInc(&nCounter); - std::string osFilename = HTTPFetchContentDispositionFilename(psResult->papszHeaders); if (osFilename.empty()) @@ -130,8 +123,9 @@ static GDALDataset *HTTPOpen(GDALOpenInfo *poOpenInfo) osFilename = "file.dat"; } - osResultFilename.Printf("/vsimem/http_%d_%s", nNewCounter, - osFilename.c_str()); + // If changing the _gdal_http_ marker, change jpgdataset.cpp that tests for it + const CPLString osResultFilename = VSIMemGenerateHiddenFilename( + std::string("_gdal_http_").append(osFilename).c_str()); VSILFILE *fp = VSIFileFromMemBuffer(osResultFilename, psResult->pabyData, psResult->nDataLen, TRUE); diff --git a/frmts/jpeg/jpgdataset.cpp b/frmts/jpeg/jpgdataset.cpp index 2d5f593efaea..a9a8029c2dc9 100644 --- a/frmts/jpeg/jpgdataset.cpp +++ b/frmts/jpeg/jpgdataset.cpp @@ -2859,7 +2859,8 @@ GDALDataset *JPGDatasetCommon::OpenFLIRRawThermalImage() GByte *pabyData = static_cast(CPLMalloc(m_abyRawThermalImage.size())); - const std::string osTmpFilename(CPLSPrintf("/vsimem/jpeg/%p", pabyData)); + const std::string osTmpFilename( + VSIMemGenerateHiddenFilename("jpeg_flir_raw")); memcpy(pabyData, m_abyRawThermalImage.data(), m_abyRawThermalImage.size()); VSILFILE *fpRaw = VSIFileFromMemBuffer(osTmpFilename.c_str(), pabyData, m_abyRawThermalImage.size(), true); @@ -3235,7 +3236,8 @@ JPGDatasetCommon *JPGDataset::OpenStage2(JPGDatasetOpenArgs *psArgs, // will unlink the temporary /vsimem file just after GDALOpen(), so // later VSIFOpenL() when reading internal overviews would fail. // Initialize them now. - if (STARTS_WITH(real_filename, "/vsimem/http_")) + if (STARTS_WITH(real_filename, "/vsimem/") && + strstr(real_filename, "_gdal_http_")) { poDS->InitInternalOverviews(); } @@ -4097,7 +4099,7 @@ void JPGAddEXIF(GDALDataType eWorkDT, GDALDataset *poSrcDS, char **papszOptions, return; } - CPLString osTmpFile(CPLSPrintf("/vsimem/ovrjpg%p", poMemDS)); + const CPLString osTmpFile(VSIMemGenerateHiddenFilename("ovrjpg")); GDALDataset *poOutDS = pCreateCopy(osTmpFile, poMemDS, 0, nullptr, GDALDummyProgress, nullptr); const bool bExifOverviewSuccess = poOutDS != nullptr; diff --git a/frmts/jpegxl/jpegxl.cpp b/frmts/jpegxl/jpegxl.cpp index 17b6ba51dc6a..826315d228ba 100644 --- a/frmts/jpegxl/jpegxl.cpp +++ b/frmts/jpegxl/jpegxl.cpp @@ -358,11 +358,9 @@ bool JPEGXLDataset::Open(GDALOpenInfo *poOpenInfo) { CPL_LSBPTR32(&nTiffDirStart); } - const std::string osTmpFilename = - CPLSPrintf("/vsimem/jxl/%p", this); - VSILFILE *fpEXIF = VSIFileFromMemBuffer( - osTmpFilename.c_str(), abyBoxBuffer.data() + 4, - abyBoxBuffer.size() - 4, false); + VSILFILE *fpEXIF = + VSIFileFromMemBuffer(nullptr, abyBoxBuffer.data() + 4, + abyBoxBuffer.size() - 4, false); int nExifOffset = 0; int nInterOffset = 0; int nGPSOffset = 0; diff --git a/frmts/jpipkak/jpipkakdataset.cpp b/frmts/jpipkak/jpipkakdataset.cpp index 9057a3f7e198..f8195d9d19c0 100644 --- a/frmts/jpipkak/jpipkakdataset.cpp +++ b/frmts/jpipkak/jpipkakdataset.cpp @@ -749,8 +749,7 @@ int JPIPKAKDataset::Initialize(const char *pszDatasetName, int bReinitializing) } // create in memory file using vsimem - CPLString osFileBoxName; - osFileBoxName.Printf("/vsimem/jpip/%s.dat", pszCid); + const CPLString osFileBoxName(VSIMemGenerateHiddenFilename("jpip")); VSILFILE *fpLL = VSIFOpenL(osFileBoxName.c_str(), "w+"); poCache->set_read_scope(KDU_META_DATABIN, nCodestream, 0); kdu_byte *pabyBuffer = (kdu_byte *)CPLMalloc(nLen); diff --git a/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp b/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp index 62ba490713b8..4b06cb443f31 100644 --- a/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp +++ b/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp @@ -31,7 +31,6 @@ #include "kmlsuperoverlaydataset.h" #include -#include #include #include #include @@ -1799,9 +1798,7 @@ KmlSuperOverlayLoadIcon(const char *pszBaseFilename, const char *pszIcon) return nullptr; } - static std::atomic nInc = 0; - osSubFilename = - CPLSPrintf("/vsimem/kmlsuperoverlay_%d_%p", nInc++, pszBaseFilename); + osSubFilename = VSIMemGenerateHiddenFilename("kmlsuperoverlay"); VSIFCloseL(VSIFileFromMemBuffer(osSubFilename, pabyBuffer, nRead, TRUE)); auto poDSIcon = std::unique_ptr(GDALDataset::Open( diff --git a/frmts/mbtiles/mbtilesdataset.cpp b/frmts/mbtiles/mbtilesdataset.cpp index 1d3549ca0d53..6ef43a125b20 100644 --- a/frmts/mbtiles/mbtilesdataset.cpp +++ b/frmts/mbtiles/mbtilesdataset.cpp @@ -1710,8 +1710,8 @@ GIntBig MBTilesVectorLayer::GetFeatureCount(int bForce) { VSIUnlink(m_osTmpFilename); } - m_osTmpFilename = - CPLSPrintf("/vsimem/mvt_%p_%d_%d.pbf", this, m_nX, m_nY); + m_osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("mvt_%d_%d.pbf", m_nX, m_nY)); VSIFCloseL(VSIFileFromMemBuffer(m_osTmpFilename, pabyDataDup, nDataSize, true)); @@ -1794,8 +1794,8 @@ OGRFeature *MBTilesVectorLayer::GetNextSrcFeature() { VSIUnlink(m_osTmpFilename); } - m_osTmpFilename = - CPLSPrintf("/vsimem/mvt_%p_%d_%d.pbf", this, m_nX, m_nY); + m_osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("mvt_%d_%d.pbf", m_nX, m_nY)); VSIFCloseL(VSIFileFromMemBuffer(m_osTmpFilename, pabyDataDup, nDataSize, true)); @@ -1903,8 +1903,8 @@ OGRFeature *MBTilesVectorLayer::GetFeature(GIntBig nFID) OGR_F_Destroy(hFeat); OGR_DS_ReleaseResultSet(m_poDS->hDS, hSQLLyr); - CPLString osTmpFilename = - CPLSPrintf("/vsimem/mvt_getfeature_%p_%d_%d.pbf", this, nX, nY); + const CPLString osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("mvt_get_feature_%d_%d.pbf", m_nX, m_nY)); VSIFCloseL( VSIFileFromMemBuffer(osTmpFilename, pabyDataDup, nDataSize, true)); @@ -1979,7 +1979,8 @@ void MBTilesDataset::InitVector(double dfMinX, double dfMinY, double dfMaxX, OGR_DS_ReleaseResultSet(hDS, hSQLLyr); } - m_osMetadataMemFilename = CPLSPrintf("/vsimem/%p_metadata.json", this); + m_osMetadataMemFilename = + VSIMemGenerateHiddenFilename("mbtiles_metadata.json"); oDoc.Save(m_osMetadataMemFilename); CPLJSONArray oVectorLayers; @@ -2556,8 +2557,7 @@ static int MBTilesGetBandCountAndTileSize(bool bIsVSICURL, OGRDataSourceH &hDS, break; } - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/%p", hSQLLyr); + const CPLString osMemFileName(VSIMemGenerateHiddenFilename("mvt_temp.db")); int nDataSize = 0; GByte *pabyData = OGR_F_GetFieldAsBinary(hFeat, 0, &nDataSize); diff --git a/frmts/mrf/PNG_band.cpp b/frmts/mrf/PNG_band.cpp index b868e6324232..b0582f346a95 100644 --- a/frmts/mrf/PNG_band.cpp +++ b/frmts/mrf/PNG_band.cpp @@ -153,7 +153,7 @@ CPLErr PNG_Codec::DecompressPNG(buf_mgr &dst, buf_mgr &src) { // Use the PNG driver for decompression of 8-bit images, as it // has optimizations for whole image decompression. - CPLString osTmpFilename(CPLSPrintf("/vsimem/mrf/%p.png", &dst)); + const CPLString osTmpFilename(VSIMemGenerateHiddenFilename("mrf.png")); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), reinterpret_cast(src_ori.buffer), src_ori.size, false)); diff --git a/frmts/mrf/Tif_band.cpp b/frmts/mrf/Tif_band.cpp index 1d69ecabad9b..04a22bc15920 100644 --- a/frmts/mrf/Tif_band.cpp +++ b/frmts/mrf/Tif_band.cpp @@ -51,9 +51,7 @@ #include "marfa.h" NAMESPACE_MRF_START -// Returns a string in /vsimem/ + prefix + count that doesn't exist when this -// function gets called It is not thread safe, open the result as soon as -// possible +// Returns a unique filename static CPLString uniq_memfname(const char *prefix) { // Define MRF_LOCAL_TMP to use local files instead of RAM @@ -61,14 +59,7 @@ static CPLString uniq_memfname(const char *prefix) #if defined(MRF_LOCAL_TMP) return CPLGenerateTempFilename(prefix); #else - CPLString fname; - VSIStatBufL statb; - static unsigned int cnt = 0; - do - { - fname.Printf("/vsimem/%s_%08x", prefix, cnt++); - } while (!VSIStatL(fname, &statb)); - return fname; + return VSIMemGenerateHiddenFilename(prefix); #endif } diff --git a/frmts/nitf/nitfbilevel.cpp b/frmts/nitf/nitfbilevel.cpp index 879dbad39582..3370c5eee608 100644 --- a/frmts/nitf/nitfbilevel.cpp +++ b/frmts/nitf/nitfbilevel.cpp @@ -33,7 +33,6 @@ #include #include "cpl_conv.h" -#include "cpl_multiproc.h" #include "cpl_string.h" #include "cpl_vsi.h" #include "gdal.h" @@ -57,10 +56,8 @@ int NITFUncompressBILEVEL(NITFImage *psImage, GByte *pabyInputData, const int nOutputBytes = (psImage->nBlockWidth * psImage->nBlockHeight + 7) / 8; - CPLString osFilename; - - osFilename.Printf("/vsimem/nitf-wrk-%ld.tif", (long)CPLGetPID()); - + const CPLString osFilename( + VSIMemGenerateHiddenFilename("nitf_bilevel.tif")); VSILFILE *fpL = VSIFOpenL(osFilename, "w+"); if (fpL == nullptr) return FALSE; diff --git a/frmts/nitf/nitfdump.c b/frmts/nitf/nitfdump.c index 6d8934490893..4dc24987d42e 100644 --- a/frmts/nitf/nitfdump.c +++ b/frmts/nitf/nitfdump.c @@ -629,10 +629,11 @@ int main(int nArgc, char **papszArgv) "CSSHPA DES")) { char szFilename[40]; - char szRadix[32]; + char szRadix[256]; if (bExtractSHPInMem) snprintf(szRadix, sizeof(szRadix), - "/vsimem/nitf_segment_%d", iSegment + 1); + VSIMemGenerateHiddenFilename( + CPLSPrintf("nitf_segment_%d", iSegment + 1))); else snprintf(szRadix, sizeof(szRadix), "nitf_segment_%d", iSegment + 1); diff --git a/frmts/nitf/nitfimage.c b/frmts/nitf/nitfimage.c index 185127fc48fd..090edc96b166 100644 --- a/frmts/nitf/nitfimage.c +++ b/frmts/nitf/nitfimage.c @@ -3847,7 +3847,7 @@ static void NITFLoadLocationTable(NITFImage *psImage) GUInt32 nHeaderOffset = 0; int i; int nTRESize; - char szTempFileName[32]; + char szTempFileName[256]; VSILFILE *fpTemp; pszTRE = @@ -3855,7 +3855,8 @@ static void NITFLoadLocationTable(NITFImage *psImage) if (pszTRE == NULL) return; - snprintf(szTempFileName, sizeof(szTempFileName), "/vsimem/%p", pszTRE); + snprintf(szTempFileName, sizeof(szTempFileName), "%s", + VSIMemGenerateHiddenFilename("nitf_tre")); fpTemp = VSIFileFromMemBuffer(szTempFileName, (GByte *)pszTRE, nTRESize, FALSE); psImage->pasLocations = diff --git a/frmts/ogcapi/gdalogcapidataset.cpp b/frmts/ogcapi/gdalogcapidataset.cpp index 7157d1979104..69750ab7526c 100644 --- a/frmts/ogcapi/gdalogcapidataset.cpp +++ b/frmts/ogcapi/gdalogcapidataset.cpp @@ -638,8 +638,7 @@ OGCAPIDataset::OpenTile(const CPLString &osURLPattern, int nMatrix, int nColumn, if (bEmptyContent) return nullptr; - CPLString osTempFile; - osTempFile.Printf("/vsimem/ogcapi/%p", this); + const CPLString osTempFile(VSIMemGenerateHiddenFilename("ogcapi")); VSIFCloseL(VSIFileFromMemBuffer(osTempFile.c_str(), reinterpret_cast(&m_osTileData[0]), m_osTileData.size(), false)); diff --git a/frmts/pdf/pdfcreatecopy.cpp b/frmts/pdf/pdfcreatecopy.cpp index 462c2b158bc6..8c72aebf4501 100644 --- a/frmts/pdf/pdfcreatecopy.cpp +++ b/frmts/pdf/pdfcreatecopy.cpp @@ -4311,7 +4311,7 @@ GDALPDFObjectNum GDALPDFBaseWriter::WriteBlock( eCompressMethod == COMPRESS_JPEG2000) { GDALDriver *poJPEGDriver = nullptr; - char szTmp[64]; + std::string osTmpfilename; char **papszOptions = nullptr; bool bEcwEncodeKeyRequiredButNotFound = false; @@ -4321,7 +4321,7 @@ GDALPDFObjectNum GDALPDFBaseWriter::WriteBlock( if (poJPEGDriver != nullptr && nJPEGQuality > 0) papszOptions = CSLAddString( papszOptions, CPLSPrintf("QUALITY=%d", nJPEGQuality)); - snprintf(szTmp, sizeof(szTmp), "/vsimem/pdftemp/%p.jpg", this); + osTmpfilename = VSIMemGenerateHiddenFilename("pdf_temp.jpg"); } else { @@ -4374,7 +4374,7 @@ GDALPDFObjectNum GDALPDFBaseWriter::WriteBlock( papszOptions = CSLAddString(papszOptions, "GMLJP2=OFF"); } } - snprintf(szTmp, sizeof(szTmp), "/vsimem/pdftemp/%p.jp2", this); + osTmpfilename = VSIMemGenerateHiddenFilename("pdf_temp.jp2"); } if (poJPEGDriver == nullptr) @@ -4396,8 +4396,8 @@ GDALPDFObjectNum GDALPDFBaseWriter::WriteBlock( } GDALDataset *poJPEGDS = - poJPEGDriver->CreateCopy(szTmp, poBlockSrcDS, FALSE, papszOptions, - pfnProgress, pProgressData); + poJPEGDriver->CreateCopy(osTmpfilename.c_str(), poBlockSrcDS, FALSE, + papszOptions, pfnProgress, pProgressData); CSLDestroy(papszOptions); if (poJPEGDS == nullptr) @@ -4409,7 +4409,8 @@ GDALPDFObjectNum GDALPDFBaseWriter::WriteBlock( GDALClose(poJPEGDS); vsi_l_offset nJPEGDataSize = 0; - GByte *pabyJPEGData = VSIGetMemFileBuffer(szTmp, &nJPEGDataSize, TRUE); + GByte *pabyJPEGData = + VSIGetMemFileBuffer(osTmpfilename.c_str(), &nJPEGDataSize, TRUE); VSIFWriteL(pabyJPEGData, static_cast(nJPEGDataSize), 1, m_fp); CPLFree(pabyJPEGData); } diff --git a/frmts/pdf/pdfdataset.cpp b/frmts/pdf/pdfdataset.cpp index cab477ab4da9..845057fd68a9 100644 --- a/frmts/pdf/pdfdataset.cpp +++ b/frmts/pdf/pdfdataset.cpp @@ -2120,7 +2120,7 @@ CPLErr PDFDataset::ReadPixels(int nReqXOff, int nReqYOff, int nReqXSize, } papszArgs = CSLAddString(papszArgs, m_osFilename.c_str()); - osTmpFilename = CPLSPrintf("/vsimem/pdf/temp_%p.ppm", this); + osTmpFilename = VSIMemGenerateHiddenFilename("pdf_temp.ppm"); VSILFILE *fpOut = VSIFOpenL(osTmpFilename, "wb"); if (fpOut != nullptr) { diff --git a/frmts/pds/isis3dataset.cpp b/frmts/pds/isis3dataset.cpp index bacaab84372f..41aa9c2c6808 100644 --- a/frmts/pds/isis3dataset.cpp +++ b/frmts/pds/isis3dataset.cpp @@ -3618,8 +3618,7 @@ void ISIS3Dataset::WriteLabel() CPLString ISIS3Dataset::SerializeAsPDL(const CPLJSONObject &oObj) { - CPLString osTmpFile( - CPLSPrintf("/vsimem/isis3_%p", oObj.GetInternalHandle())); + const CPLString osTmpFile(VSIMemGenerateHiddenFilename("isis3_pdl")); VSILFILE *fpTmp = VSIFOpenL(osTmpFile, "wb+"); SerializeAsPDL(fpTmp, oObj); VSIFCloseL(fpTmp); diff --git a/frmts/pds/vicardataset.cpp b/frmts/pds/vicardataset.cpp index 26a51bdf7790..8f022e60f24b 100644 --- a/frmts/pds/vicardataset.cpp +++ b/frmts/pds/vicardataset.cpp @@ -1913,8 +1913,8 @@ void VICARDataset::BuildLabelPropertyGeoTIFF(CPLJSONObject &oLabel) // Create a in-memory GeoTIFF file - char szFilename[100] = {}; - snprintf(szFilename, sizeof(szFilename), "/vsimem/vicar_tmp_%p.tif", this); + const std::string osTmpFilename( + VSIMemGenerateHiddenFilename("vicar_tmp.tif")); GDALDriver *poGTiffDriver = GDALDriver::FromHandle(GDALGetDriverByName("GTiff")); if (poGTiffDriver == nullptr) @@ -1923,8 +1923,8 @@ void VICARDataset::BuildLabelPropertyGeoTIFF(CPLJSONObject &oLabel) return; } const char *const apszOptions[] = {"GEOTIFF_VERSION=1.0", nullptr}; - auto poDS = std::unique_ptr( - poGTiffDriver->Create(szFilename, 1, 1, 1, GDT_Byte, apszOptions)); + auto poDS = std::unique_ptr(poGTiffDriver->Create( + osTmpFilename.c_str(), 1, 1, 1, GDT_Byte, apszOptions)); if (!poDS) return; poDS->SetSpatialRef(&m_oSRS); @@ -1935,14 +1935,14 @@ void VICARDataset::BuildLabelPropertyGeoTIFF(CPLJSONObject &oLabel) poDS.reset(); // Open it with libtiff/libgeotiff - VSILFILE *fpL = VSIFOpenL(szFilename, "r"); + VSILFILE *fpL = VSIFOpenL(osTmpFilename.c_str(), "r"); if (fpL == nullptr) { - VSIUnlink(szFilename); + VSIUnlink(osTmpFilename.c_str()); return; } - TIFF *hTIFF = VSI_TIFFOpen(szFilename, "r", fpL); + TIFF *hTIFF = VSI_TIFFOpen(osTmpFilename.c_str(), "r", fpL); CPLAssert(hTIFF); GTIF *hGTIF = GTIFNew(hTIFF); @@ -2008,7 +2008,7 @@ void VICARDataset::BuildLabelPropertyGeoTIFF(CPLJSONObject &oLabel) XTIFFClose(hTIFF); CPL_IGNORE_RET_VAL(VSIFCloseL(fpL)); - VSIUnlink(szFilename); + VSIUnlink(osTmpFilename.c_str()); } /************************************************************************/ @@ -2320,8 +2320,8 @@ void VICARDataset::ReadProjectionFromGeoTIFFGroup() // We will build a in-memory temporary GeoTIFF file from the VICAR GEOTIFF // metadata items. - char szFilename[100] = {}; - snprintf(szFilename, sizeof(szFilename), "/vsimem/vicar_tmp_%p.tif", this); + const std::string osTmpFilename( + VSIMemGenerateHiddenFilename("vicar_tmp.tif")); /* -------------------------------------------------------------------- */ /* Initialization of libtiff and libgeotiff. */ @@ -2332,11 +2332,11 @@ void VICARDataset::ReadProjectionFromGeoTIFFGroup() /* -------------------------------------------------------------------- */ /* Initialize access to the memory geotiff structure. */ /* -------------------------------------------------------------------- */ - VSILFILE *fpL = VSIFOpenL(szFilename, "w"); + VSILFILE *fpL = VSIFOpenL(osTmpFilename.c_str(), "w"); if (fpL == nullptr) return; - TIFF *hTIFF = VSI_TIFFOpen(szFilename, "w", fpL); + TIFF *hTIFF = VSI_TIFFOpen(osTmpFilename.c_str(), "w", fpL); if (hTIFF == nullptr) { @@ -2451,7 +2451,7 @@ void VICARDataset::ReadProjectionFromGeoTIFFGroup() /* Get georeferencing from file. */ /* -------------------------------------------------------------------- */ auto poGTiffDS = - std::unique_ptr(GDALDataset::Open(szFilename)); + std::unique_ptr(GDALDataset::Open(osTmpFilename.c_str())); if (poGTiffDS) { auto poSRS = poGTiffDS->GetSpatialRef(); @@ -2469,7 +2469,7 @@ void VICARDataset::ReadProjectionFromGeoTIFFGroup() GDALDataset::SetMetadataItem(GDALMD_AREA_OR_POINT, pszAreaOrPoint); } - VSIUnlink(szFilename); + VSIUnlink(osTmpFilename.c_str()); } /************************************************************************/ diff --git a/frmts/plmosaic/plmosaicdataset.cpp b/frmts/plmosaic/plmosaicdataset.cpp index a8632e275d1a..fd759dd1a60c 100644 --- a/frmts/plmosaic/plmosaicdataset.cpp +++ b/frmts/plmosaic/plmosaicdataset.cpp @@ -1329,6 +1329,7 @@ GDALDataset *PLMosaicDataset::GetMetaTile(int tile_x, int tile_y) CreateMosaicCachePathIfNecessary(); + bool bUnlink = false; VSILFILE *fp = osCachePathRoot.size() ? VSIFOpenL(osTmpFilename, "wb") : nullptr; if (fp) @@ -1349,9 +1350,10 @@ GDALDataset *PLMosaicDataset::GetMetaTile(int tile_x, int tile_y) FlushDatasetsCache(); nCacheMaxSize = 1; } - osTmpFilename = - CPLSPrintf("/vsimem/single_tile_plmosaic_cache/%s/%d_%d.tif", - osMosaic.c_str(), tile_x, tile_y); + bUnlink = true; + osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("single_tile_plmosaic_cache_%s_%d_%d.tif", + osMosaic.c_str(), tile_x, tile_y)); fp = VSIFOpenL(osTmpFilename, "wb"); if (fp) { @@ -1362,7 +1364,7 @@ GDALDataset *PLMosaicDataset::GetMetaTile(int tile_x, int tile_y) CPLHTTPDestroyResult(psResult); GDALDataset *poDS = OpenAndInsertNewDataset(osTmpFilename, osTilename); - if (STARTS_WITH(osTmpFilename, "/vsimem/single_tile_plmosaic_cache/")) + if (bUnlink) VSIUnlink(osTilename); return poDS; diff --git a/frmts/rasterlite/rasterlitecreatecopy.cpp b/frmts/rasterlite/rasterlitecreatecopy.cpp index fba77104823c..9de3a39f5e0d 100644 --- a/frmts/rasterlite/rasterlitecreatecopy.cpp +++ b/frmts/rasterlite/rasterlitecreatecopy.cpp @@ -581,8 +581,8 @@ GDALDataset *RasterliteCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, return nullptr; } - CPLString osTempFileName; - osTempFileName.Printf("/vsimem/%p", hDS); + const CPLString osTempFileName( + VSIMemGenerateHiddenFilename("rasterlite_tile")); int nTileId = 0; int nBlocks = 0; diff --git a/frmts/rasterlite/rasterlitedataset.cpp b/frmts/rasterlite/rasterlitedataset.cpp index a85cf6fafa4a..8f12d77d64fd 100644 --- a/frmts/rasterlite/rasterlitedataset.cpp +++ b/frmts/rasterlite/rasterlitedataset.cpp @@ -156,8 +156,8 @@ CPLErr RasterliteBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) return CE_None; } - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/%p", this); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("rasterlite_tile")); #ifdef RASTERLITE_DEBUG if (nBand == 1) @@ -912,8 +912,8 @@ int RasterliteDataset::GetBlockParams(OGRLayerH hRasterLyr, int nLevelIn, return FALSE; } - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/%p", this); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("rasterlite_tile")); VSILFILE *fp = VSIFileFromMemBuffer(osMemFileName.c_str(), pabyData, nDataSize, FALSE); VSIFCloseL(fp); diff --git a/frmts/rasterlite/rasterliteoverviews.cpp b/frmts/rasterlite/rasterliteoverviews.cpp index bc6599d9fb0c..2a0c9cc3c8f1 100644 --- a/frmts/rasterlite/rasterliteoverviews.cpp +++ b/frmts/rasterlite/rasterliteoverviews.cpp @@ -350,8 +350,8 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char *pszResampling, return CE_Failure; } - CPLString osTempFileName; - osTempFileName.Printf("/vsimem/%p", hDS); + const CPLString osTempFileName( + VSIMemGenerateHiddenFilename("rasterlite_tile")); int nTileId = 0; int nBlocks = 0; diff --git a/frmts/rmf/rmfjpeg.cpp b/frmts/rmf/rmfjpeg.cpp index 8c4b7fd78f73..b7dc56abbbcc 100644 --- a/frmts/rmf/rmfjpeg.cpp +++ b/frmts/rmf/rmfjpeg.cpp @@ -31,6 +31,7 @@ #include #include "cpl_conv.h" +#include "cpl_vsi.h" #include "rmfdataset.h" #include "../mem/memdataset.h" @@ -46,13 +47,10 @@ size_t RMFDataset::JPEGDecompress(const GByte *pabyIn, GUInt32 nSizeIn, nSizeIn < 2) return 0; - CPLString osTmpFilename; - VSILFILE *fp; + const CPLString osTmpFilename(VSIMemGenerateHiddenFilename("rmfjpeg.jpg")); - osTmpFilename.Printf("/vsimem/rmfjpeg/%p.jpg", pabyIn); - - fp = VSIFileFromMemBuffer(osTmpFilename, const_cast(pabyIn), - nSizeIn, FALSE); + VSILFILE *fp = VSIFileFromMemBuffer( + osTmpFilename, const_cast(pabyIn), nSizeIn, FALSE); if (fp == nullptr) { @@ -165,8 +163,7 @@ size_t RMFDataset::JPEGCompress(const GByte *pabyIn, GUInt32 nSizeIn, poMemDS->AddMEMBand(hBand); } - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/rmfjpeg/%p.jpg", pabyIn); + const CPLString osTmpFilename(VSIMemGenerateHiddenFilename("rmfjpeg.jpg")); char szQuality[32] = {}; if (poDS != nullptr && poDS->sHeader.iJpegQuality > 0) diff --git a/frmts/stacta/stactadataset.cpp b/frmts/stacta/stactadataset.cpp index 55c4cdfc47e9..0603efb561a3 100644 --- a/frmts/stacta/stactadataset.cpp +++ b/frmts/stacta/stactadataset.cpp @@ -489,8 +489,13 @@ CPLErr STACTARawDataset::IRasterIO( return CE_Failure; } VSIFCloseL(fp); - const CPLString osMEMFilename("/vsimem/stacta/" + - osURL); + const CPLString osMEMFilename( + VSIMemGenerateHiddenFilename( + std::string("stacta_") + .append(CPLString(osURL) + .replaceAll("/", "_") + .replaceAll("\\", "_")) + .c_str())); VSIFCloseL(VSIFileFromMemBuffer(osMEMFilename, pabyBuf, nSize, TRUE)); poTileDS = std::unique_ptr( diff --git a/frmts/wcs/wcsdataset.cpp b/frmts/wcs/wcsdataset.cpp index 009b035fcfd5..c37e62374a51 100644 --- a/frmts/wcs/wcsdataset.cpp +++ b/frmts/wcs/wcsdataset.cpp @@ -720,7 +720,7 @@ GDALDataset *WCSDataset::GDALOpenResult(CPLHTTPResult *psResult) #endif // Eventually we should be looking at mime info and stuff to figure // out an optimal filename, but for now we just use a fixed one. - osResultFilename = CPLString().Printf("/vsimem/wcs/%p/wcsresult.dat", this); + osResultFilename = VSIMemGenerateHiddenFilename("wcsresult.dat"); VSILFILE *fp = VSIFileFromMemBuffer(osResultFilename.c_str(), pabyData, nDataLen, FALSE); diff --git a/frmts/wms/wmsutils.cpp b/frmts/wms/wmsutils.cpp index 75ddddc6598a..b9f044c929d0 100644 --- a/frmts/wms/wmsutils.cpp +++ b/frmts/wms/wmsutils.cpp @@ -70,9 +70,7 @@ void URLPrepare(CPLString &url) CPLString BufferToVSIFile(GByte *buffer, size_t size) { - CPLString file_name; - - file_name.Printf("/vsimem/wms/%p/wmsresult.dat", buffer); + const CPLString file_name(VSIMemGenerateHiddenFilename("wmsresult.dat")); VSILFILE *f = VSIFileFromMemBuffer(file_name.c_str(), buffer, size, false); if (f == nullptr) return CPLString(); diff --git a/gcore/gdaljp2abstractdataset.cpp b/gcore/gdaljp2abstractdataset.cpp index fc63d9e28578..98b37bec1270 100644 --- a/gcore/gdaljp2abstractdataset.cpp +++ b/gcore/gdaljp2abstractdataset.cpp @@ -368,6 +368,8 @@ void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources) return; } + const std::string osTmpDir = VSIMemGenerateHiddenFilename("gmljp2"); + // Find feature collections. int nLayersAtCC = 0; int nLayersAtGC = 0; @@ -451,7 +453,8 @@ void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources) if (psFC != nullptr) { - osGMLTmpFile = CPLSPrintf("/vsimem/gmljp2_%p/my.gml", this); + osGMLTmpFile = + CPLFormFilename(osTmpDir.c_str(), "my.gml", nullptr); // Create temporary .gml file. CPLSerializeXMLTreeToFile(psFC, osGMLTmpFile); } @@ -486,8 +489,8 @@ void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources) CPLSPrintf("xml:%s", pszBoxName)); if (papszBoxData != nullptr) { - osXSDTmpFile = CPLSPrintf( - "/vsimem/gmljp2_%p/my.xsd", this); + osXSDTmpFile = CPLFormFilename( + osTmpDir.c_str(), "my.xsd", nullptr); CPL_IGNORE_RET_VAL( VSIFCloseL(VSIFileFromMemBuffer( osXSDTmpFile, @@ -551,7 +554,7 @@ void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources) "No GML driver found to read feature collection"); } - VSIRmdirRecursive(CPLSPrintf("/vsimem/gmljp2_%p", this)); + VSIRmdirRecursive(osTmpDir.c_str()); } } @@ -589,8 +592,8 @@ void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources) // Create temporary .kml file. CPLXMLNode *const psKML = psGCorGMLJP2FeaturesChildIter->psChild; - CPLString osKMLTmpFile( - CPLSPrintf("/vsimem/gmljp2_%p_my.kml", this)); + const CPLString osKMLTmpFile( + VSIMemGenerateHiddenFilename("my.kml")); CPLSerializeXMLTreeToFile(psKML, osKMLTmpFile); GDALDatasetUniquePtr poTmpDS(GDALDataset::Open( diff --git a/gcore/gdaljp2metadata.cpp b/gcore/gdaljp2metadata.cpp index 198a80ef9d9f..3852ecd93fd1 100644 --- a/gcore/gdaljp2metadata.cpp +++ b/gcore/gdaljp2metadata.cpp @@ -2593,6 +2593,8 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2V2(int nXSize, int nYSize, "\n", osRootGMLId.c_str(), osGridCoverage.c_str()); + const std::string osTmpDir = VSIMemGenerateHiddenFilename("gmljp2"); + /* -------------------------------------------------------------------- */ /* Process metadata, annotations and features collections. */ /* -------------------------------------------------------------------- */ @@ -2756,7 +2758,7 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2V2(int nXSize, int nYSize, if (hSrcDS) { CPLString osTmpFile = - CPLSPrintf("/vsimem/gmljp2_%p/%d/%s.gml", this, i, + CPLSPrintf("%s/%d/%s.gml", osTmpDir.c_str(), i, CPLGetBasename(aoGMLFiles[i].osFile)); char **papszOptions = nullptr; papszOptions = @@ -2864,7 +2866,7 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2V2(int nXSize, int nYSize, !aoGMLFiles[i].osRemoteResource.empty()) { osTmpFile = - CPLSPrintf("/vsimem/gmljp2_%p/%d/%s.gml", this, i, + CPLSPrintf("%s/%d/%s.gml", osTmpDir.c_str(), i, CPLGetBasename(aoGMLFiles[i].osFile)); GMLJP2V2BoxDesc oDesc; @@ -3044,7 +3046,7 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2V2(int nXSize, int nYSize, if (hSrcDS) { CPLString osTmpFile = - CPLSPrintf("/vsimem/gmljp2_%p/%d/%s.kml", this, i, + CPLSPrintf("%s/%d/%s.kml", osTmpDir.c_str(), i, CPLGetBasename(aoAnnotations[i].osFile)); char **papszOptions = nullptr; if (aoAnnotations.size() > 1) @@ -3260,7 +3262,7 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2V2(int nXSize, int nYSize, for (auto &poGMLBox : apoGMLBoxes) delete poGMLBox; - VSIRmdirRecursive(CPLSPrintf("/vsimem/gmljp2_%p", this)); + VSIRmdirRecursive(osTmpDir.c_str()); return poGMLData; } diff --git a/gcore/gdaljp2structure.cpp b/gcore/gdaljp2structure.cpp index 6520f901ab02..d115e9cc782d 100644 --- a/gcore/gdaljp2structure.cpp +++ b/gcore/gdaljp2structure.cpp @@ -251,8 +251,7 @@ static void DumpGeoTIFFBox(CPLXMLNode *psBox, GDALJP2Box &oBox, static_cast(GDALGetDriverByName("VRT")); if (pabyBoxData && poVRTDriver) { - CPLString osTmpFilename( - CPLSPrintf("/vsimem/tmp_%p.tif", oBox.GetFILE())); + const CPLString osTmpFilename(VSIMemGenerateHiddenFilename("tmp.tif")); CPL_IGNORE_RET_VAL(VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename, pabyBoxData, nBoxDataLength, FALSE))); CPLPushErrorHandler(CPLQuietErrorHandler); @@ -267,8 +266,8 @@ static void DumpGeoTIFFBox(CPLXMLNode *psBox, GDALJP2Box &oBox, } if (poDS) { - CPLString osTmpVRTFilename( - CPLSPrintf("/vsimem/tmp_%p.vrt", oBox.GetFILE())); + const CPLString osTmpVRTFilename( + CPLResetExtension(osTmpFilename.c_str(), "vrt")); GDALDataset *poVRTDS = poVRTDriver->CreateCopy( osTmpVRTFilename, poDS, FALSE, nullptr, nullptr, nullptr); GDALClose(poVRTDS); diff --git a/gcore/gdalmultidim.cpp b/gcore/gdalmultidim.cpp index b46bf17780fe..77576028b34b 100644 --- a/gcore/gdalmultidim.cpp +++ b/gcore/gdalmultidim.cpp @@ -8187,10 +8187,10 @@ std::shared_ptr GDALMDArrayResampled::Create( "Setting geolocation array from variables %s and %s", poLongVar->GetName().c_str(), poLatVar->GetName().c_str()); - std::string osFilenameLong = - CPLSPrintf("/vsimem/%p/longitude.tif", poParent.get()); - std::string osFilenameLat = - CPLSPrintf("/vsimem/%p/latitude.tif", poParent.get()); + const std::string osFilenameLong = + VSIMemGenerateHiddenFilename("longitude.tif"); + const std::string osFilenameLat = + VSIMemGenerateHiddenFilename("latitude.tif"); std::unique_ptr poTmpLongDS( longDimCount == 1 ? poLongVar->AsClassicDataset(0, 0) diff --git a/gcore/gdalmultidim_gridded.cpp b/gcore/gdalmultidim_gridded.cpp index 4a0741a903c7..56142a31f4fe 100644 --- a/gcore/gdalmultidim_gridded.cpp +++ b/gcore/gdalmultidim_gridded.cpp @@ -665,9 +665,8 @@ GDALMDArray::GetGridded(const std::string &osGridOptions, } // Create a in-memory vector layer with (X,Y) points - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/GDALMDArray::GetGridded_%p_%p.%s", this, - pOptions, pszExt); + const std::string osTmpFilename(VSIMemGenerateHiddenFilename( + std::string("tmp.").append(pszExt).c_str())); auto poDS = std::unique_ptr( poDrv->Create(osTmpFilename.c_str(), 0, 0, 0, GDT_Unknown, nullptr)); if (!poDS) diff --git a/gcore/gdalorienteddataset.cpp b/gcore/gdalorienteddataset.cpp index 11e49b4ebcd7..15e00d6941b0 100644 --- a/gcore/gdalorienteddataset.cpp +++ b/gcore/gdalorienteddataset.cpp @@ -149,8 +149,7 @@ CPLErr GDALOrientedRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, } else { - osTmpName = - CPLSPrintf("/vsimem/_gdalorienteddataset/%p.tif", this); + osTmpName = VSIMemGenerateHiddenFilename(nullptr); } } GDALTranslateOptions *psOptions = diff --git a/gcore/gdalpython.cpp b/gcore/gdalpython.cpp index af964c91400d..4f944c52e3ae 100644 --- a/gcore/gdalpython.cpp +++ b/gcore/gdalpython.cpp @@ -378,7 +378,7 @@ static bool LoadPythonAPI() "-c", pszPrintVersion, nullptr}; const CPLString osTmpFilename( - "/vsimem/LoadPythonAPI/out.txt"); + VSIMemGenerateHiddenFilename("out.txt")); VSILFILE *fout = VSIFOpenL(osTmpFilename, "wb+"); if (CPLSpawn(apszArgv, nullptr, fout, FALSE) == 0) { diff --git a/ogr/ogr_geocoding.cpp b/ogr/ogr_geocoding.cpp index 412d7d7557c1..c9821807a6b0 100644 --- a/ogr/ogr_geocoding.cpp +++ b/ogr/ogr_geocoding.cpp @@ -471,8 +471,9 @@ static OGRLayer *OGRGeocodeGetCacheLayer(OGRGeocodingSessionH hSession, (EQUAL(osExt, "SQLITE") || EQUAL(osExt, "CSV"))) { CPLFree(hSession->pszCacheFilename); - hSession->pszCacheFilename = CPLStrdup(CPLSPrintf( - "/vsimem/%s.%s", CACHE_LAYER_NAME, osExt.c_str())); + hSession->pszCacheFilename = + CPLStrdup(VSIMemGenerateHiddenFilename(CPLSPrintf( + "%s.%s", CACHE_LAYER_NAME, osExt.c_str()))); CPLDebug("OGR", "Switch geocode cache file to %s", hSession->pszCacheFilename); poDS = reinterpret_cast( diff --git a/ogr/ogrsf_frmts/arrow/ogrfeatherdriver.cpp b/ogr/ogrsf_frmts/arrow/ogrfeatherdriver.cpp index 8e5dad1c0053..27639faf4421 100644 --- a/ogr/ogrsf_frmts/arrow/ogrfeatherdriver.cpp +++ b/ogr/ogrsf_frmts/arrow/ogrfeatherdriver.cpp @@ -90,7 +90,7 @@ static bool IsArrowIPCStream(GDALOpenInfo *poOpenInfo) } const std::string osTmpFilename( - CPLSPrintf("/vsimem/_arrow/%p", poOpenInfo)); + VSIMemGenerateHiddenFilename("arrow")); auto fp = VSIVirtualHandleUniquePtr(VSIFileFromMemBuffer( osTmpFilename.c_str(), poOpenInfo->pabyHeader, nSizeToRead, false)); diff --git a/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp b/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp index cf8a7cd6b81d..98e387324589 100644 --- a/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp +++ b/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp @@ -960,7 +960,7 @@ char **OGRCSVLayer::AutodetectFieldTypes(CSLConstList papszOpenOptions, nRead = VSIFReadL(pszData, 1, nRequested, fpCSV); pszData[nRead] = 0; - osTmpMemFile = CPLSPrintf("/vsimem/tmp%p", this); + osTmpMemFile = VSIMemGenerateHiddenFilename("temp.csv"); fp = VSIFileFromMemBuffer(osTmpMemFile.c_str(), reinterpret_cast(pszData), nRead, FALSE); diff --git a/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp b/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp index 82ae661544f0..b3c5d419254e 100644 --- a/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp +++ b/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp @@ -56,6 +56,8 @@ class OGRCSWLayer final : public OGRLayer CPLString osQuery; CPLString osCSWWhere; + std::string m_osTmpDir{}; + GDALDataset *FetchGetRecords(); GIntBig GetFeatureCountWithHits(); void BuildQuery(); @@ -258,6 +260,8 @@ OGRCSWLayer::OGRCSWLayer(OGRCSWDataSource *poDSIn) } poSRS->Release(); + + m_osTmpDir = VSIMemGenerateHiddenFilename("csw"); } /************************************************************************/ @@ -268,8 +272,7 @@ OGRCSWLayer::~OGRCSWLayer() { poFeatureDefn->Release(); GDALClose(poBaseDS); - CPLString osTmpDirName = CPLSPrintf("/vsimem/tempcsw_%p", this); - OGRWFSRecursiveUnlink(osTmpDirName); + VSIRmdirRecursive(m_osTmpDir.c_str()); } /************************************************************************/ @@ -531,8 +534,7 @@ GDALDataset *OGRCSWLayer::FetchGetRecords() return nullptr; } - CPLString osTmpDirName = CPLSPrintf("/vsimem/tempcsw_%p", this); - VSIMkdir(osTmpDirName, 0); + VSIMkdir(m_osTmpDir.c_str(), 0); GByte *pabyData = psResult->pabyData; int nDataLen = psResult->nDataLen; @@ -549,10 +551,10 @@ GDALDataset *OGRCSWLayer::FetchGetRecords() CPLString osTmpFileName; - osTmpFileName = osTmpDirName + "/file.gfs"; + osTmpFileName = m_osTmpDir + "/file.gfs"; VSIUnlink(osTmpFileName); - osTmpFileName = osTmpDirName + "/file.gml"; + osTmpFileName = m_osTmpDir + "/file.gml"; VSILFILE *fp = VSIFileFromMemBuffer(osTmpFileName, pabyData, nDataLen, TRUE); diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp index 4d7b4510a193..426f07ef90ef 100644 --- a/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp +++ b/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp @@ -195,8 +195,9 @@ int OGRGeoJSONDataSource::Open(GDALOpenInfo *poOpenInfo, bool bEmitError = true; if (eGeoJSONSourceService == nSrcType) { - const CPLString osTmpFilename = CPLSPrintf( - "/vsimem/%p/%s", this, CPLGetFilename(poOpenInfo->pszFilename)); + const CPLString osTmpFilename = + VSIMemGenerateHiddenFilename(CPLSPrintf( + "geojson_%s", CPLGetFilename(poOpenInfo->pszFilename))); VSIFCloseL(VSIFileFromMemBuffer(osTmpFilename, (GByte *)pszGeoData_, nGeoDataLen_, TRUE)); pszGeoData_ = nullptr; diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonseqdriver.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsonseqdriver.cpp index 0ac1eb612e30..b1fa548ec798 100644 --- a/ogr/ogrsf_frmts/geojson/ogrgeojsonseqdriver.cpp +++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonseqdriver.cpp @@ -818,7 +818,7 @@ bool OGRGeoJSONSeqDataSource::Open(GDALOpenInfo *poOpenInfo, if (poOpenInfo->eAccess == GA_Update) return false; - m_osTmpFile = CPLSPrintf("/vsimem/geojsonseq/%p", this); + m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq"); m_fp = VSIFileFromMemBuffer( m_osTmpFile.c_str(), reinterpret_cast(CPLStrdup(poOpenInfo->pszFilename)), @@ -842,7 +842,7 @@ bool OGRGeoJSONSeqDataSource::Open(GDALOpenInfo *poOpenInfo, } else { - m_osTmpFile = CPLSPrintf("/vsimem/geojsonseq/%p", this); + m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq"); m_fp = VSIFileFromMemBuffer( m_osTmpFile.c_str(), reinterpret_cast(pszStoredContent), @@ -873,7 +873,7 @@ bool OGRGeoJSONSeqDataSource::Open(GDALOpenInfo *poOpenInfo, return false; } - m_osTmpFile = CPLSPrintf("/vsimem/geojsonseq/%p", this); + m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq"); m_fp = VSIFileFromMemBuffer(m_osTmpFile.c_str(), pResult->pabyData, pResult->nDataLen, true); pResult->pabyData = nullptr; diff --git a/ogr/ogrsf_frmts/gml/ogr_gml.h b/ogr/ogrsf_frmts/gml/ogr_gml.h index 84aa6d54c72b..1a0e89c94409 100644 --- a/ogr/ogrsf_frmts/gml/ogr_gml.h +++ b/ogr/ogrsf_frmts/gml/ogr_gml.h @@ -150,6 +150,7 @@ class OGRGMLDataSource final : public OGRDataSource // input related parameters. CPLString osFilename{}; CPLString osXSDFilename{}; + bool m_bUnlinkXSDFilename = false; IGMLReader *poReader; bool bOutIsTempFile; diff --git a/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp b/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp index 9848c665a36a..8bee7da6d9f9 100644 --- a/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp +++ b/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp @@ -269,9 +269,10 @@ OGRGMLDataSource::~OGRGMLDataSource() delete poStoredGMLFeature; - if (osXSDFilename.compare(CPLSPrintf("/vsimem/tmp_gml_xsd_%p.xsd", this)) == - 0) + if (m_bUnlinkXSDFilename) + { VSIUnlink(osXSDFilename); + } } /************************************************************************/ @@ -532,7 +533,8 @@ bool OGRGMLDataSource::Open(GDALOpenInfo *poOpenInfo) } } } - else if (STARTS_WITH(pszFilename, "/vsimem/tempwfs_")) + else if (STARTS_WITH(pszFilename, "/vsimem/") && + strstr(pszFilename, "_ogr_wfs_")) { // http://regis.intergraph.com/wfs/dcmetro/request.asp? returns a // Who knows what servers can return? When @@ -1101,8 +1103,10 @@ bool OGRGMLDataSource::Open(GDALOpenInfo *poOpenInfo) psResult->pabyData != nullptr) { bHasFoundXSD = true; - osXSDFilename = CPLSPrintf( - "/vsimem/tmp_gml_xsd_%p.xsd", this); + m_bUnlinkXSDFilename = true; + osXSDFilename = + VSIMemGenerateHiddenFilename( + "tmp_ogr_gml.xsd"); VSILFILE *fpMem = VSIFileFromMemBuffer( osXSDFilename, psResult->pabyData, psResult->nDataLen, TRUE); diff --git a/ogr/ogrsf_frmts/gmlas/ogrgmlasxsdcache.cpp b/ogr/ogrsf_frmts/gmlas/ogrgmlasxsdcache.cpp index b855d71020ee..acbe77fe5fee 100644 --- a/ogr/ogrsf_frmts/gmlas/ogrgmlasxsdcache.cpp +++ b/ogr/ogrsf_frmts/gmlas/ogrgmlasxsdcache.cpp @@ -152,7 +152,8 @@ bool GMLASXSDCache::CacheAllGML321() CPLHTTPResult *psResult = CPLHTTPFetch(pszHTTPZIP, nullptr); if (psResult && psResult->nDataLen) { - const std::string osZIPFilename(CPLSPrintf("/vsimem/%p.zip", this)); + const std::string osZIPFilename( + VSIMemGenerateHiddenFilename("temp.zip")); auto fpZIP = VSIFileFromMemBuffer(osZIPFilename.c_str(), psResult->pabyData, psResult->nDataLen, FALSE); @@ -220,7 +221,8 @@ bool GMLASXSDCache::CacheAllISO20070417() CPLHTTPResult *psResult = CPLHTTPFetch(pszHTTPZIP, nullptr); if (psResult && psResult->nDataLen) { - const std::string osZIPFilename(CPLSPrintf("/vsimem/%p.zip", this)); + const std::string osZIPFilename( + VSIMemGenerateHiddenFilename("temp.zip")); auto fpZIP = VSIFileFromMemBuffer(osZIPFilename.c_str(), psResult->pabyData, psResult->nDataLen, FALSE); diff --git a/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp b/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp index 23d6f530e237..abc99854405b 100644 --- a/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp +++ b/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp @@ -243,8 +243,8 @@ GDALColorTable *GDALGPKGMBTilesLikeRasterBand::GetColorTable() const int nBytes = sqlite3_column_bytes(hStmt, 0); GByte *pabyRawData = reinterpret_cast( const_cast(sqlite3_column_blob(hStmt, 0))); - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("gpkg_read_tile")); VSILFILE *fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyRawData, nBytes, FALSE); VSIFCloseL(fp); @@ -915,8 +915,8 @@ GByte *GDALGPKGMBTilesLikePseudoDataset::ReadTile(int nRow, int nCol, (m_eDT == GDT_Byte) ? 0 : sqlite3_column_int64(hStmt, 1); GByte *pabyRawData = static_cast( const_cast(sqlite3_column_blob(hStmt, 0))); - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("gpkg_read_tile")); VSILFILE *fp = VSIFileFromMemBuffer(osMemFileName.c_str(), pabyRawData, nBytes, FALSE); VSIFCloseL(fp); @@ -1847,8 +1847,8 @@ CPLErr GDALGPKGMBTilesLikePseudoDataset::WriteTileInternal() nRow, nCol, m_nZoomLevel); } - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_write_tile_%p", this); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("gpkg_write_tile")); const char *pszDriverName = "PNG"; bool bTileDriverSupports1Band = false; bool bTileDriverSupports2Bands = false; @@ -2727,8 +2727,8 @@ GDALGPKGMBTilesLikePseudoDataset::FlushRemainingShiftedTiles(bool bPartialFlush) GByte *pabyRawData = const_cast(static_cast( sqlite3_column_blob(hNewStmt, 0))); - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("gpkg_read_tile")); VSILFILE *fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyRawData, nBytes, FALSE); VSIFCloseL(fp); diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp index 61ee94970372..92590ca0b831 100644 --- a/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp +++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp @@ -9200,8 +9200,8 @@ static CPLString GPKG_GDAL_GetMemFileFromBlob(sqlite3_value **argv) int nBytes = sqlite3_value_bytes(argv[0]); const GByte *pabyBLOB = reinterpret_cast(sqlite3_value_blob(argv[0])); - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/GPKG_GDAL_GetMemFileFromBlob_%p", argv); + const CPLString osMemFileName( + VSIMemGenerateHiddenFilename("GPKG_GDAL_GetMemFileFromBlob")); VSILFILE *fp = VSIFileFromMemBuffer( osMemFileName.c_str(), const_cast(pabyBLOB), nBytes, FALSE); VSIFCloseL(fp); diff --git a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp index f03210037ac3..5f06d4d61653 100644 --- a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp +++ b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp @@ -261,7 +261,7 @@ int OGRGPSBabelDataSource::Open(const char *pszDatasourceName, if (pszOptionUseTempFile && CPLTestBool(pszOptionUseTempFile)) osTmpFileName = CPLGenerateTempFilename(nullptr); else - osTmpFileName.Printf("/vsimem/ogrgpsbabeldatasource_%p", this); + osTmpFileName = VSIMemGenerateHiddenFilename("gpsbabel"); bool bRet = false; if (IsSpecialFile(pszFilename)) diff --git a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp index eca3cc717701..3eeb68d2c384 100644 --- a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp +++ b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp @@ -115,7 +115,8 @@ OGRGPSBabelDriverIdentifyInternal(GDALOpenInfo *poOpenInfo, { CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); const char *const apszArgs[] = {"gpsbabel", "-V", nullptr}; - CPLString osTmpFileName("/vsimem/gpsbabel_tmp.tmp"); + const CPLString osTmpFileName = + VSIMemGenerateHiddenFilename("gpsbabel"); VSILFILE *tmpfp = VSIFOpenL(osTmpFileName, "wb"); bGPSBabelFound = CPLSpawn(apszArgs, nullptr, tmpfp, FALSE) == 0; VSIFCloseL(tmpfp); diff --git a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp index f9bae27b9fc8..bea9d5a41fd6 100644 --- a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp +++ b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp @@ -193,7 +193,7 @@ int OGRGPSBabelWriteDataSource::Create(const char *pszNameIn, if (pszOptionUseTempFile && CPLTestBool(pszOptionUseTempFile)) osTmpFileName = CPLGenerateTempFilename(nullptr); else - osTmpFileName.Printf("/vsimem/ogrgpsbabeldatasource_%p", this); + osTmpFileName = VSIMemGenerateHiddenFilename("gpsbabel"); poGPXDS = poGPXDriver->Create(osTmpFileName.c_str(), 0, 0, 0, GDT_Unknown, papszOptions); diff --git a/ogr/ogrsf_frmts/mvt/ogrmvtdataset.cpp b/ogr/ogrsf_frmts/mvt/ogrmvtdataset.cpp index 7b37c500dd48..de3166fac2f3 100644 --- a/ogr/ogrsf_frmts/mvt/ogrmvtdataset.cpp +++ b/ogr/ogrsf_frmts/mvt/ogrmvtdataset.cpp @@ -2804,7 +2804,7 @@ GDALDataset *OGRMVTDataset::OpenDirectory(GDALOpenInfo *poOpenInfo) OGRMVTDataset *poDS = new OGRMVTDataset(nullptr); const CPLString osMetadataMemFilename = - CPLSPrintf("/vsimem/%p_metadata.json", poDS); + VSIMemGenerateHiddenFilename("mvt_metadata.json"); if (!LoadMetadata(osMetadataFile, osMetadataContent, oVectorLayers, oTileStatLayers, oBounds, poDS->m_poSRS, poDS->m_dfTopXOrigin, poDS->m_dfTopYOrigin, @@ -4484,7 +4484,8 @@ static void GZIPCompress(std::string &oTileBuffer) { if (!oTileBuffer.empty()) { - CPLString osTmpFilename(CPLSPrintf("/vsimem/%p.gz", &oTileBuffer)); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("mvt_temp.gz")); CPLString osTmpGZipFilename("/vsigzip/" + osTmpFilename); VSILFILE *fpGZip = VSIFOpenL(osTmpGZipFilename, "wb"); if (fpGZip) diff --git a/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp b/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp index 45920d639f2a..c39eb52bcf13 100644 --- a/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp +++ b/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp @@ -906,8 +906,8 @@ void OGROpenFileGDBDataSource::GuessJPEGQuality(int nOverviewCount) } if (nJPEGSize) { - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/_openfilegdb/%p.jpg", this); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("openfilegdb.jpg")); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), const_cast(pabyData + nJPEGOffset), nJPEGSize, @@ -1551,8 +1551,8 @@ CPLErr GDALOpenFileGDBRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, return CE_Failure; } - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/_openfilegdb/%p.jpg", this); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("openfilegdb.jpg")); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), const_cast(pabyData + nJPEGOffset), nJPEGSize, false)); @@ -1674,8 +1674,8 @@ CPLErr GDALOpenFileGDBRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, return CE_Failure; } - CPLString osTmpFilename; - osTmpFilename.Printf("/vsimem/_openfilegdb/%p.j2k", this); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("openfilegdb.j2k")); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), const_cast(pabyData + nJPEGOffset), nJPEGSize, false)); diff --git a/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp b/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp index 6dfe592d232d..b3c2976516dd 100644 --- a/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp +++ b/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp @@ -2885,7 +2885,7 @@ int OGROSMDataSource::Open(const char *pszFilename, } m_bInMemoryNodesFile = true; - m_osNodesFilename.Printf("/vsimem/osm_temp_nodes_%p", this); + m_osNodesFilename = VSIMemGenerateHiddenFilename("osm_temp_nodes"); m_fpNodes = VSIFOpenL(m_osNodesFilename, "wb+"); if (m_fpNodes == nullptr) { @@ -2971,7 +2971,7 @@ bool OGROSMDataSource::CreateTempDB() } else { - m_osTmpDBName.Printf("/vsimem/osm_temp_%p.sqlite", this); + m_osTmpDBName = VSIMemGenerateHiddenFilename("osm_temp.sqlite"); // On 32 bit, the virtual memory space is scarce, so we need to // reserve it right now. Will not hurt on 64 bit either. diff --git a/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1dataset.cpp b/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1dataset.cpp index 78c0eb3f670c..7ad724680d37 100644 --- a/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1dataset.cpp +++ b/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1dataset.cpp @@ -626,7 +626,11 @@ GDALDataset *OGRPLScenesDataV1Dataset::OpenRasterScene(GDALOpenInfo *poOpenInfo, { // Set a dummy name so that PAM goes here CPLPushErrorHandler(CPLQuietErrorHandler); - poOutDS->SetDescription("/vsimem/tmp/ogrplscenesDataV1"); + + const std::string osTmpFilename = + VSIMemGenerateHiddenFilename("ogrplscenesDataV1"); + + poOutDS->SetDescription(osTmpFilename.c_str()); /* Attach scene metadata. */ poLayer->SetAttributeFilter( @@ -663,8 +667,9 @@ GDALDataset *OGRPLScenesDataV1Dataset::OpenRasterScene(GDALOpenInfo *poOpenInfo, delete poFeat; poOutDS->FlushCache(false); - VSIUnlink("/vsimem/tmp/ogrplscenesDataV1"); - VSIUnlink("/vsimem/tmp/ogrplscenesDataV1.aux.xml"); + VSIUnlink(osTmpFilename.c_str()); + VSIUnlink( + std::string(osTmpFilename).append(".aux.xml").c_str()); CPLPopErrorHandler(); } } diff --git a/ogr/ogrsf_frmts/pmtiles/ogrpmtilesdataset.cpp b/ogr/ogrsf_frmts/pmtiles/ogrpmtilesdataset.cpp index ab82a4d9bfe5..53fa0db2510c 100644 --- a/ogr/ogrsf_frmts/pmtiles/ogrpmtilesdataset.cpp +++ b/ogr/ogrsf_frmts/pmtiles/ogrpmtilesdataset.cpp @@ -239,7 +239,8 @@ bool OGRPMTilesDataset::Open(GDALOpenInfo *poOpenInfo) CPLDebugOnly("PMTiles", "Metadata = %s", posMetadata->c_str()); m_osMetadata = *posMetadata; - m_osMetadataFilename = CPLSPrintf("/vsimem/pmtiles/metadata_%p.json", this); + m_osMetadataFilename = + VSIMemGenerateHiddenFilename("pmtiles_metadata.json"); VSIFCloseL(VSIFileFromMemBuffer(m_osMetadataFilename.c_str(), reinterpret_cast(&m_osMetadata[0]), m_osMetadata.size(), false)); diff --git a/ogr/ogrsf_frmts/pmtiles/ogrpmtilesvectorlayer.cpp b/ogr/ogrsf_frmts/pmtiles/ogrpmtilesvectorlayer.cpp index c6eea3ae3bc3..6bd80339f7f2 100644 --- a/ogr/ogrsf_frmts/pmtiles/ogrpmtilesvectorlayer.cpp +++ b/ogr/ogrsf_frmts/pmtiles/ogrpmtilesvectorlayer.cpp @@ -155,8 +155,8 @@ OGRwkbGeometryType OGRPMTilesVectorLayer::GuessGeometryType( } osTileData = *posStr; - std::string osTmpFilename = - CPLSPrintf("/vsimem/mvt_%p_%u_%u.pbf", poDS, sTile.x, sTile.y); + const std::string osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("pmtiles_%u_%u.pbf", sTile.x, sTile.y)); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), reinterpret_cast(&osTileData[0]), osTileData.size(), false)); @@ -226,8 +226,8 @@ GIntBig OGRPMTilesVectorLayer::GetTotalFeatureCount() const } osTileData = *posStr; - std::string osTmpFilename = CPLSPrintf( - "/vsimem/mvt_%p_%u_%u_getfeaturecount.pbf", this, sTile.x, sTile.y); + const std::string osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("pmtiles_%u_%u_getfeaturecount.pbf", sTile.x, sTile.y)); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), reinterpret_cast(&osTileData[0]), osTileData.size(), false)); @@ -300,8 +300,8 @@ OGRFeature *OGRPMTilesVectorLayer::GetFeature(GIntBig nFID) } std::string osTileData = *posStr; - std::string osTmpFilename = CPLSPrintf( - "/vsimem/mvt_%p_%u_%u_getfeature.pbf", this, sTile.x, sTile.y); + const std::string osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("pmtiles_getfeature_%u_%u.pbf", sTile.x, sTile.y)); VSIFCloseL(VSIFileFromMemBuffer(osTmpFilename.c_str(), reinterpret_cast(&osTileData[0]), osTileData.size(), false)); @@ -408,8 +408,8 @@ std::unique_ptr OGRPMTilesVectorLayer::GetNextSrcFeature() } m_poTileDS.reset(); - const std::string osTmpFilename = - CPLSPrintf("/vsimem/mvt_%p_%u_%u.pbf", this, sTile.x, sTile.y); + const std::string osTmpFilename = VSIMemGenerateHiddenFilename( + CPLSPrintf("pmtiles_%u_%u.pbf", sTile.x, sTile.y)); VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename.c_str(), reinterpret_cast(&m_osTileData[0]), diff --git a/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp b/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp index eb102e8c3b8a..9e747cd2d06d 100644 --- a/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp +++ b/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp @@ -1556,7 +1556,7 @@ bool OGRShapeDataSource::UncompressIfNeeded() nTotalUncompressedSize < static_cast(CPLGetUsablePhysicalRAM() / 10))) { - osTemporaryDir = CPLSPrintf("/vsimem/_shapedriver/%p", this); + osTemporaryDir = VSIMemGenerateHiddenFilename("shapedriver"); } CPLDebug("Shape", "Uncompressing to %s", osTemporaryDir.c_str()); diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp index 879b335b5e0e..6e74a85440f7 100644 --- a/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp +++ b/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp @@ -851,9 +851,7 @@ OGRLayer *OGRSQLiteExecuteSQL(GDALDataset *poDS, const char *pszStatement, } char *pszTmpDBName = static_cast(CPLMalloc(256)); - char szPtr[32]; - snprintf(szPtr, sizeof(szPtr), "%p", pszTmpDBName); - snprintf(pszTmpDBName, 256, "/vsimem/ogr2sqlite/temp_%s.db", szPtr); + snprintf(pszTmpDBName, 256, "%s", VSIMemGenerateHiddenFilename("temp.db")); OGRSQLiteDataSource *poSQLiteDS = nullptr; bool bSpatialiteDB = false; @@ -881,9 +879,8 @@ OGRLayer *OGRSQLiteExecuteSQL(GDALDataset *poDS, const char *pszStatement, { bTried = true; char *pszCachedFilename = static_cast(CPLMalloc(256)); - snprintf(szPtr, sizeof(szPtr), "%p", pszCachedFilename); - snprintf(pszCachedFilename, 256, - "/vsimem/ogr2sqlite/reference_%s.db", szPtr); + snprintf(pszCachedFilename, 256, "%s", + VSIMemGenerateHiddenFilename("reference.db")); char **papszOptions = CSLAddString(nullptr, "SPATIALITE=YES"); OGRSQLiteDataSource *poCachedDS = new OGRSQLiteDataSource(); const int nRet = diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp index a7a0b6a3aa83..8674380598ee 100644 --- a/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp +++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp @@ -33,7 +33,6 @@ #include #include -#include "cpl_atomic_ops.h" #include "cpl_conv.h" #include "cpl_error.h" #include "cpl_string.h" @@ -54,7 +53,6 @@ typedef struct sqlite3_vfs *pDefaultVFS; pfnNotifyFileOpenedType pfn; void *pfnUserData; - int nCounter; } OGRSQLiteVFSAppDataStruct; #define GET_UNDERLYING_VFS(pVFS) \ @@ -243,22 +241,19 @@ static const sqlite3_io_methods OGRSQLiteIOMethods = { nullptr, // xUnfetch }; -static int OGRSQLiteVFSOpen(sqlite3_vfs *pVFS, const char *zName, +static int OGRSQLiteVFSOpen(sqlite3_vfs *pVFS, const char *zNameIn, sqlite3_file *pFile, int flags, int *pOutFlags) { #ifdef DEBUG_IO - CPLDebug("SQLITE", "OGRSQLiteVFSOpen(%s, %d)", zName ? zName : "(null)", + CPLDebug("SQLITE", "OGRSQLiteVFSOpen(%s, %d)", zNameIn ? zNameIn : "(null)", flags); #endif OGRSQLiteVFSAppDataStruct *pAppData = static_cast(pVFS->pAppData); - if (zName == nullptr) - { - zName = CPLSPrintf("/vsimem/sqlite/%p_%d", pVFS, - CPLAtomicInc(&(pAppData->nCounter))); - } + const std::string osName( + zNameIn ? zNameIn : VSIMemGenerateHiddenFilename("sqlitevfs")); OGRSQLiteFileStruct *pMyFile = reinterpret_cast(pFile); @@ -266,17 +261,17 @@ static int OGRSQLiteVFSOpen(sqlite3_vfs *pVFS, const char *zName, pMyFile->bDeleteOnClose = FALSE; pMyFile->pszFilename = nullptr; if (flags & SQLITE_OPEN_READONLY) - pMyFile->fp = VSIFOpenL(zName, "rb"); + pMyFile->fp = VSIFOpenL(osName.c_str(), "rb"); else if (flags & SQLITE_OPEN_CREATE) { VSIStatBufL sStatBufL; - if (VSIStatExL(zName, &sStatBufL, VSI_STAT_EXISTS_FLAG) == 0) - pMyFile->fp = VSIFOpenL(zName, "rb+"); + if (VSIStatExL(osName.c_str(), &sStatBufL, VSI_STAT_EXISTS_FLAG) == 0) + pMyFile->fp = VSIFOpenL(osName.c_str(), "rb+"); else - pMyFile->fp = VSIFOpenL(zName, "wb+"); + pMyFile->fp = VSIFOpenL(osName.c_str(), "wb+"); } else if (flags & SQLITE_OPEN_READWRITE) - pMyFile->fp = VSIFOpenL(zName, "rb+"); + pMyFile->fp = VSIFOpenL(osName.c_str(), "rb+"); else pMyFile->fp = nullptr; @@ -290,12 +285,12 @@ static int OGRSQLiteVFSOpen(sqlite3_vfs *pVFS, const char *zName, pfnNotifyFileOpenedType pfn = pAppData->pfn; if (pfn) { - pfn(pAppData->pfnUserData, zName, pMyFile->fp); + pfn(pAppData->pfnUserData, osName.c_str(), pMyFile->fp); } pMyFile->pMethods = &OGRSQLiteIOMethods; pMyFile->bDeleteOnClose = (flags & SQLITE_OPEN_DELETEONCLOSE); - pMyFile->pszFilename = CPLStrdup(zName); + pMyFile->pszFilename = CPLStrdup(osName.c_str()); if (pOutFlags != nullptr) *pOutFlags = flags; @@ -514,7 +509,6 @@ sqlite3_vfs *OGRSQLiteCreateVFS(pfnNotifyFileOpenedType pfn, void *pfnUserData) pVFSAppData->pDefaultVFS = pDefaultVFS; pVFSAppData->pfn = pfn; pVFSAppData->pfnUserData = pfnUserData; - pVFSAppData->nCounter = 0; pMyVFS->iVersion = 2; pMyVFS->szOsFile = sizeof(OGRSQLiteFileStruct); diff --git a/ogr/ogrsf_frmts/wfs/ogr_wfs.h b/ogr/ogrsf_frmts/wfs/ogr_wfs.h index 91ca09f34f3d..6178c496e16a 100644 --- a/ogr/ogrsf_frmts/wfs/ogr_wfs.h +++ b/ogr/ogrsf_frmts/wfs/ogr_wfs.h @@ -41,7 +41,7 @@ #include "ogr_swq.h" const CPLXMLNode *WFSFindNode(const CPLXMLNode *psXML, const char *pszRootName); -void OGRWFSRecursiveUnlink(const char *pszName); + CPLString WFS_TurnSQLFilterToOGCFilter(const swq_expr_node *poExpr, OGRDataSource *poDS, OGRFeatureDefn *poFDefn, int nVersion, @@ -145,6 +145,8 @@ class OGRWFSLayer final : public OGRLayer std::vector m_aosSupportedCRSList{}; OGRLayer::GetSupportedSRSListRetType m_apoSupportedCRSList{}; + std::string m_osTmpDir{}; + public: OGRWFSLayer(OGRWFSDataSource *poDS, OGRSpatialReference *poSRS, int bAxisOrderAlreadyInverted, const char *pszBaseURL, @@ -257,6 +259,11 @@ class OGRWFSLayer final : public OGRLayer OGRErr SetActiveSRS(int iGeomField, const OGRSpatialReference *poSRS) override; + + const std::string &GetTmpDir() const + { + return m_osTmpDir; + } }; /************************************************************************/ @@ -290,6 +297,8 @@ class OGRWFSJoinLayer final : public OGRLayer CPLString osFeatureTypes; + std::string m_osTmpDir{}; + OGRWFSJoinLayer(OGRWFSDataSource *poDS, const swq_select *psSelectInfo, const CPLString &osGlobalFilter); CPLString MakeGetFeatureURL(int bRequestHits = FALSE); diff --git a/ogr/ogrsf_frmts/wfs/ogroapifdriver.cpp b/ogr/ogrsf_frmts/wfs/ogroapifdriver.cpp index 652d4a0d816e..d0b038aa03f9 100644 --- a/ogr/ogrsf_frmts/wfs/ogroapifdriver.cpp +++ b/ogr/ogrsf_frmts/wfs/ogroapifdriver.cpp @@ -1890,7 +1890,7 @@ void OGROAPIFLayer::EstablishFeatureDefn() if (!m_poDS->DownloadJSon(osURL, oDoc)) return; - CPLString osTmpFilename(CPLSPrintf("/vsimem/oapif_%p.json", this)); + const CPLString osTmpFilename(VSIMemGenerateHiddenFilename("oapif.json")); oDoc.Save(osTmpFilename); std::unique_ptr poDS(GDALDataset::FromHandle( GDALOpenEx(osTmpFilename, GDAL_OF_VECTOR | GDAL_OF_INTERNAL, nullptr, @@ -2134,7 +2134,8 @@ OGRFeature *OGROAPIFLayer::GetNextRawFeature() } } - CPLString osTmpFilename(CPLSPrintf("/vsimem/oapif_%p.json", this)); + const CPLString osTmpFilename( + VSIMemGenerateHiddenFilename("oapif.json")); m_oCurDoc.Save(osTmpFilename); m_poUnderlyingDS = std::unique_ptr(GDALDataset::FromHandle( diff --git a/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp b/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp index c87ae09dd349..b591f084908b 100644 --- a/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp +++ b/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp @@ -267,7 +267,7 @@ OGRLayer *OGRWFSDataSource::GetLayerByName(const char *pszNameIn) return poLayerMetadataLayer; osLayerMetadataTmpFileName = - CPLSPrintf("/vsimem/tempwfs_%p/WFSLayerMetadata.csv", this); + VSIMemGenerateHiddenFilename("WFSLayerMetadata.csv"); osLayerMetadataCSV = "layer_name,title,abstract\n" + osLayerMetadataCSV; VSIFCloseL(VSIFileFromMemBuffer(osLayerMetadataTmpFileName, @@ -1911,9 +1911,7 @@ void OGRWFSDataSource::LoadMultipleLayerDefn(const char *pszLayerName, return; } - CPLString osTmpFileName; - - osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this); + const CPLString osTmpFileName = VSIMemGenerateHiddenFilename("file.xsd"); CPLSerializeXMLTreeToFile(psSchema, osTmpFileName); std::vector aosClasses; diff --git a/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp b/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp index f024b1d02b76..0e8c82e84749 100644 --- a/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp +++ b/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp @@ -40,7 +40,9 @@ OGRWFSJoinLayer::OGRWFSJoinLayer(OGRWFSDataSource *poDSIn, bDistinct(psSelectInfo->query_mode == SWQM_DISTINCT_LIST), poBaseDS(nullptr), poBaseLayer(nullptr), bReloadNeeded(false), bHasFetched(false), bPagingActive(false), nPagingStartIndex(0), - nFeatureRead(0), nFeatureCountRequested(0) + nFeatureRead(0), nFeatureCountRequested(0), + // If changing that, change in the GML driver too + m_osTmpDir(VSIMemGenerateHiddenFilename("_ogr_wfs_")) { CPLString osName("join_"); CPLString osLayerName = psSelectInfo->table_defs[0].table_name; @@ -178,7 +180,7 @@ OGRWFSJoinLayer::OGRWFSJoinLayer(OGRWFSDataSource *poDSIn, for (int i = 0; i < (int)apoLayers.size(); i++) { CPLString osTmpFileName = - CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", apoLayers[i]); + CPLSPrintf("%s/file.xsd", apoLayers[i]->GetTmpDir().c_str()); CPLPushErrorHandler(CPLQuietErrorHandler); CPLXMLNode *psSchema = CPLParseXMLFile(osTmpFileName); CPLPopErrorHandler(); @@ -199,8 +201,7 @@ OGRWFSJoinLayer::OGRWFSJoinLayer(OGRWFSDataSource *poDSIn, } if (psGlobalSchema) { - CPLString osTmpFileName = - CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this); + CPLString osTmpFileName = CPLSPrintf("%s/file.xsd", m_osTmpDir.c_str()); CPLSerializeXMLTreeToFile(psGlobalSchema, osTmpFileName); CPLDestroyXMLNode(psGlobalSchema); } @@ -217,8 +218,7 @@ OGRWFSJoinLayer::~OGRWFSJoinLayer() if (poBaseDS != nullptr) GDALClose(poBaseDS); - CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this); - OGRWFSRecursiveUnlink(osTmpDirName); + VSIRmdirRecursive(m_osTmpDir.c_str()); } /************************************************************************/ @@ -430,7 +430,7 @@ GDALDataset *OGRWFSJoinLayer::FetchGetFeature() /* Try streaming when the output format is GML and that we have a .xsd */ /* that we are able to understand */ - CPLString osXSDFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this); + CPLString osXSDFileName = CPLSPrintf("%s/file.xsd", m_osTmpDir.c_str()); VSIStatBufL sBuf; if (CPLTestBool(CPLGetConfigOption("OGR_WFS_USE_STREAMING", "YES")) && VSIStatL(osXSDFileName, &sBuf) == 0 && @@ -487,8 +487,7 @@ GDALDataset *OGRWFSJoinLayer::FetchGetFeature() return nullptr; } - CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this); - VSIMkdir(osTmpDirName, 0); + VSIMkdir(m_osTmpDir.c_str(), 0); GByte *pabyData = psResult->pabyData; int nDataLen = psResult->nDataLen; @@ -504,10 +503,10 @@ GDALDataset *OGRWFSJoinLayer::FetchGetFeature() CPLString osTmpFileName; - osTmpFileName = osTmpDirName + "/file.gfs"; + osTmpFileName = m_osTmpDir + "/file.gfs"; VSIUnlink(osTmpFileName); - osTmpFileName = osTmpDirName + "/file.gml"; + osTmpFileName = m_osTmpDir + "/file.gml"; VSILFILE *fp = VSIFileFromMemBuffer(osTmpFileName, pabyData, nDataLen, TRUE); diff --git a/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp b/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp index e1d384f3a04a..5773e38c75e3 100644 --- a/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp +++ b/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp @@ -33,44 +33,6 @@ #include "cpl_http.h" #include "parsexsd.h" -/************************************************************************/ -/* OGRWFSRecursiveUnlink() */ -/************************************************************************/ - -void OGRWFSRecursiveUnlink(const char *pszName) - -{ - char **papszFileList = VSIReadDir(pszName); - - for (int i = 0; papszFileList != nullptr && papszFileList[i] != nullptr; - i++) - { - VSIStatBufL sStatBuf; - - if (EQUAL(papszFileList[i], ".") || EQUAL(papszFileList[i], "..")) - continue; - - CPLString osFullFilename = - CPLFormFilename(pszName, papszFileList[i], nullptr); - - if (VSIStatL(osFullFilename, &sStatBuf) == 0) - { - if (VSI_ISREG(sStatBuf.st_mode)) - { - VSIUnlink(osFullFilename); - } - else if (VSI_ISDIR(sStatBuf.st_mode)) - { - OGRWFSRecursiveUnlink(osFullFilename); - } - } - } - - CSLDestroy(papszFileList); - - VSIRmdir(pszName); -} - /************************************************************************/ /* OGRWFSLayer() */ /************************************************************************/ @@ -93,6 +55,9 @@ OGRWFSLayer::OGRWFSLayer(OGRWFSDataSource *poDSIn, OGRSpatialReference *poSRSIn, nPagingStartIndex(0), nFeatureRead(0), pszRequiredOutputFormat(nullptr) { SetDescription(pszName); + + // If changing that, change in the GML driver too + m_osTmpDir = VSIMemGenerateHiddenFilename("_ogr_wfs_"); } /************************************************************************/ @@ -114,9 +79,9 @@ OGRWFSLayer *OGRWFSLayer::Clone() pszRequiredOutputFormat ? CPLStrdup(pszRequiredOutputFormat) : nullptr; /* Copy existing schema file if already found */ - CPLString osSrcFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this); + CPLString osSrcFileName = CPLSPrintf("%s/file.xsd", m_osTmpDir.c_str()); CPLString osTargetFileName = - CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", poDupLayer); + CPLSPrintf("%s/file.xsd", poDupLayer->m_osTmpDir.c_str()); CPL_IGNORE_RET_VAL(CPLCopyFile(osTargetFileName, osSrcFileName)); return poDupLayer; @@ -148,8 +113,7 @@ OGRWFSLayer::~OGRWFSLayer() delete poFetchedFilterGeom; - CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this); - OGRWFSRecursiveUnlink(osTmpDirName); + VSIRmdirRecursive(m_osTmpDir.c_str()); CPLFree(pszRequiredOutputFormat); } @@ -312,7 +276,7 @@ OGRFeatureDefn *OGRWFSLayer::ParseSchema(const CPLXMLNode *psSchema) CPLString osTmpFileName; - osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this); + osTmpFileName = CPLSPrintf("%s/file.xsd", m_osTmpDir.c_str()); CPLSerializeXMLTreeToFile(psSchema, osTmpFileName); std::vector aosClasses; @@ -803,8 +767,7 @@ GDALDataset *OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures) /* Try streaming when the output format is GML and that we have a .xsd */ /* that we are able to understand */ - CPLString osXSDFileName = - CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this); + CPLString osXSDFileName = CPLSPrintf("%s/file.xsd", m_osTmpDir.c_str()); VSIStatBufL sBuf; GDALDriver *poDriver = nullptr; if ((osOutputFormat.empty() || @@ -922,8 +885,7 @@ GDALDataset *OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures) if (psResult->pszContentType) pszContentType = psResult->pszContentType; - const std::string osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this); - VSIMkdir(osTmpDirName.c_str(), 0); + VSIMkdir(m_osTmpDir.c_str(), 0); GByte *pabyData = psResult->pabyData; int nDataLen = psResult->nDataLen; @@ -934,11 +896,11 @@ GDALDataset *OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures) CPLHTTPParseMultipartMime(psResult)) { bIsMultiPart = true; - OGRWFSRecursiveUnlink(osTmpDirName.c_str()); - VSIMkdir(osTmpDirName.c_str(), 0); + VSIRmdirRecursive(m_osTmpDir.c_str()); + VSIMkdir(m_osTmpDir.c_str(), 0); for (int i = 0; i < psResult->nMimePartCount; i++) { - CPLString osTmpFileName = osTmpDirName + "/"; + CPLString osTmpFileName = m_osTmpDir + "/"; pszAttachmentFilename = OGRWFSFetchContentDispositionFilename( psResult->pasMimePart[i].papszHeaders); @@ -1038,31 +1000,31 @@ GDALDataset *OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures) if (!bIsMultiPart) { if (bJSON) - osTmpFileName = osTmpDirName + "/file.geojson"; + osTmpFileName = m_osTmpDir + "/file.geojson"; else if (bZIP) - osTmpFileName = osTmpDirName + "/file.zip"; + osTmpFileName = m_osTmpDir + "/file.zip"; else if (bCSV) - osTmpFileName = osTmpDirName + "/file.csv"; + osTmpFileName = m_osTmpDir + "/file.csv"; else if (bKML) - osTmpFileName = osTmpDirName + "/file.kml"; + osTmpFileName = m_osTmpDir + "/file.kml"; else if (bKMZ) - osTmpFileName = osTmpDirName + "/file.kmz"; + osTmpFileName = m_osTmpDir + "/file.kmz"; else if (bFlatGeobuf) - osTmpFileName = osTmpDirName + "/file.fgb"; + osTmpFileName = m_osTmpDir + "/file.fgb"; /* GML is a special case. It needs the .xsd file that has been saved */ /* as file.xsd, so we cannot used the attachment filename */ else if (pszAttachmentFilename && !EQUAL(CPLGetExtension(pszAttachmentFilename), "GML")) { - osTmpFileName = osTmpDirName + "/"; + osTmpFileName = m_osTmpDir + "/"; osTmpFileName += pszAttachmentFilename; } else { - osTmpFileName = osTmpDirName + "/file.gfs"; + osTmpFileName = m_osTmpDir + "/file.gfs"; VSIUnlink(osTmpFileName); - osTmpFileName = osTmpDirName + "/file.gml"; + osTmpFileName = m_osTmpDir + "/file.gml"; } VSILFILE *fp = @@ -1083,7 +1045,7 @@ GDALDataset *OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures) { pabyData = nullptr; nDataLen = 0; - osTmpFileName = osTmpDirName; + osTmpFileName = m_osTmpDir; } CPLHTTPDestroyResult(psResult); @@ -1620,8 +1582,8 @@ GIntBig OGRWFSLayer::ExecuteGetFeatureResultTypeHits() if (psResult->pszContentType != nullptr && strstr(psResult->pszContentType, "application/zip") != nullptr) { - CPLString osTmpFileName; - osTmpFileName.Printf("/vsimem/wfstemphits_%p.zip", this); + const CPLString osTmpFileName( + VSIMemGenerateHiddenFilename("wfstemphits.zip")); VSILFILE *fp = VSIFileFromMemBuffer(osTmpFileName, psResult->pabyData, psResult->nDataLen, FALSE); VSIFCloseL(fp); diff --git a/port/cpl_vsi.h b/port/cpl_vsi.h index 634f599451e8..5133f17b1296 100644 --- a/port/cpl_vsi.h +++ b/port/cpl_vsi.h @@ -547,6 +547,8 @@ GByte CPL_DLL *VSIGetMemFileBuffer(const char *pszFilename, vsi_l_offset *pnDataLength, int bUnlinkAndSeize); +const char CPL_DLL *VSIMemGenerateHiddenFilename(const char *pszFilename); + /** Callback used by VSIStdoutSetRedirection() */ typedef size_t (*VSIWriteFunction)(const void *ptr, size_t size, size_t nmemb, FILE *stream); diff --git a/port/cpl_vsi_mem.cpp b/port/cpl_vsi_mem.cpp index e5099e9c20ba..9f90a033046b 100644 --- a/port/cpl_vsi_mem.cpp +++ b/port/cpl_vsi_mem.cpp @@ -43,10 +43,12 @@ #endif #include +#include #include #include #include #include +#include #include // c++17 or VS2017 @@ -70,6 +72,39 @@ //! @cond Doxygen_Suppress +// szHIDDEN_DIRNAME is for files created by VSIMemGenerateHiddenFilename(pszFilename). +// Such files are of the form "/vsimem/.#!HIDDEN!#./{counter}/{pszFilename}" +// +// The high-level design constraint is that "/vsimem/.#!HIDDEN!#." acts as a +// "side" hiearchy, but still under the "/vsimem/" namespace, so that code +// having special processing of filenames starting with /vsimem/ can still work. +// The structure of the returned filename is also such that those files form +// independent hierarchies, i.e. the tree generated by a +// VSIMemGenerateHiddenFilename() is "invisible" from the one returned by +// another call to it. +// +// As a consequence: +// - we don't want ".#!HIDDEN!#." to be listed in VSIReadDir("/vsimem/") +// - we don't want content under ""/vsimem/.#!HIDDEN!#" to be deleted by +// VSIRmdirRecursive("/vsimem/") +// - we don't want the creation of a file (or directory) called +// "/vsimem/.#!HIDDEN!#./{counter}/{pszFilename}" +// to cause the implicit creation of "/vsimem/.#!HIDDEN!#./{counter}" and +// "/vsimem/.#!HIDDEN!#". This is done so that users don't have to care about +// cleaning such implicit directories that are upper in the hiearchy w.r.t. +// to what we return to them. +// - But we want the creation of file or directory +// "/vsimem/.#!HIDDEN!#./{counter}/{pszFilename}/something_added_by_user" +// to cause "/vsimem/.#!HIDDEN!#./{counter}/{pszFilename}" to be implicitly +// created as a directory, so they can list it, or recursively delete it. +// - we want VSIReadDirRecursive("/vsimem/.#!HIDDEN!#.") to list everything +// under it (for debugging purposes) +// - we want VSIRmdirRecursive("/vsimem/.#!HIDDEN!#.") to remove everything +// under it (for debugging purposes) +// + +constexpr const char *szHIDDEN_DIRNAME = "/vsimem/.#!HIDDEN!#."; + /* ** Notes on Multithreading: ** @@ -195,6 +230,7 @@ class VSIMemFilesystemHandler final : public VSIFilesystemHandler int Unlink(const char *pszFilename) override; int Mkdir(const char *pszDirname, long nMode) override; int Rmdir(const char *pszDirname) override; + int RmdirRecursive(const char *pszDirname) override; char **ReadDirEx(const char *pszDirname, int nMaxFiles) override; int Rename(const char *oldpath, const char *newpath) override; GIntBig GetDiskFreeSpace(const char *pszDirname) override; @@ -807,6 +843,18 @@ int VSIMemFilesystemHandler::Mkdir(const char *pszPathname, long /* nMode */) CPLMutexHolder oHolder(&hMutex); const CPLString osPathname = NormalizePath(pszPathname); + if (STARTS_WITH(osPathname.c_str(), szHIDDEN_DIRNAME)) + { + if (osPathname.size() == strlen(szHIDDEN_DIRNAME)) + return 0; + // "/vsimem/.#!HIDDEN!#./{unique_counter}" + else if (osPathname.find('/', strlen(szHIDDEN_DIRNAME) + 1) == + std::string::npos) + return 0; + + // If "/vsimem/.#!HIDDEN!#./{unique_counter}/user_directory", then + // accept creating an explicit directory + } if (oFileList.find(osPathname) != oFileList.end()) { @@ -836,6 +884,69 @@ int VSIMemFilesystemHandler::Rmdir(const char *pszPathname) return Unlink(pszPathname); } +/************************************************************************/ +/* RmdirRecursive() */ +/************************************************************************/ + +int VSIMemFilesystemHandler::RmdirRecursive(const char *pszDirname) +{ + CPLMutexHolder oHolder(&hMutex); + + const CPLString osPath = NormalizePath(pszDirname); + const size_t nPathLen = osPath.size(); + int ret = 0; + if (osPath == "/vsimem") + { + // Clean-up all files under pszDirname, except hidden directories + // if called from "/vsimem" + for (auto iter = oFileList.begin(); iter != oFileList.end(); + /* no automatic increment */) + { + const char *pszFilePath = iter->second->osFilename.c_str(); + const size_t nFileLen = iter->second->osFilename.size(); + if (nFileLen > nPathLen && + memcmp(pszFilePath, osPath.c_str(), nPathLen) == 0 && + pszFilePath[nPathLen] == '/' && + !STARTS_WITH(pszFilePath, szHIDDEN_DIRNAME)) + { + iter = oFileList.erase(iter); + } + else + { + ++iter; + } + } + } + else + { + ret = -1; + for (auto iter = oFileList.begin(); iter != oFileList.end(); + /* no automatic increment */) + { + const char *pszFilePath = iter->second->osFilename.c_str(); + const size_t nFileLen = iter->second->osFilename.size(); + if (nFileLen >= nPathLen && + memcmp(pszFilePath, osPath.c_str(), nPathLen) == 0 && + (nFileLen == nPathLen || pszFilePath[nPathLen] == '/')) + { + // If VSIRmdirRecursive() is used correctly, it should at + // least delete the directory on which it has been called + ret = 0; + iter = oFileList.erase(iter); + } + else + { + ++iter; + } + } + + // Make sure that it always succeed on the root hidden directory + if (osPath == szHIDDEN_DIRNAME) + ret = 0; + } + return ret; +} + /************************************************************************/ /* ReadDirEx() */ /************************************************************************/ @@ -848,41 +959,89 @@ char **VSIMemFilesystemHandler::ReadDirEx(const char *pszPath, int nMaxFiles) const CPLString osPath = NormalizePath(pszPath); char **papszDir = nullptr; - size_t nPathLen = osPath.size(); - - if (nPathLen > 0 && osPath.back() == '/') - nPathLen--; + const size_t nPathLen = osPath.size(); // In case of really big number of files in the directory, CSLAddString // can be slow (see #2158). We then directly build the list. int nItems = 0; int nAllocatedItems = 0; - for (const auto &iter : oFileList) + if (osPath == szHIDDEN_DIRNAME) { - const char *pszFilePath = iter.second->osFilename.c_str(); - if (EQUALN(osPath, pszFilePath, nPathLen) && - pszFilePath[nPathLen] == '/' && - strstr(pszFilePath + nPathLen + 1, "/") == nullptr) + // Special mode for hidden filenames. + // "/vsimem/.#!HIDDEN!#./{counter}" subdirectories are not explicitly + // created so they do not appear in oFileList, but their subcontent + // (e.g "/vsimem/.#!HIDDEN!#./{counter}/foo") does + std::set oSetSubDirs; + for (const auto &iter : oFileList) { - if (nItems == 0) + const char *pszFilePath = iter.second->osFilename.c_str(); + if (iter.second->osFilename.size() > nPathLen && + memcmp(pszFilePath, osPath.c_str(), nPathLen) == 0) { - papszDir = static_cast(CPLCalloc(2, sizeof(char *))); - nAllocatedItems = 1; + char *pszItem = CPLStrdup(pszFilePath + nPathLen + 1); + char *pszSlash = strchr(pszItem, '/'); + if (pszSlash) + *pszSlash = 0; + if (cpl::contains(oSetSubDirs, pszItem)) + { + CPLFree(pszItem); + continue; + } + oSetSubDirs.insert(pszItem); + + if (nItems == 0) + { + papszDir = + static_cast(CPLCalloc(2, sizeof(char *))); + nAllocatedItems = 1; + } + else if (nItems >= nAllocatedItems) + { + nAllocatedItems = nAllocatedItems * 2; + papszDir = static_cast(CPLRealloc( + papszDir, (nAllocatedItems + 2) * sizeof(char *))); + } + + papszDir[nItems] = pszItem; + papszDir[nItems + 1] = nullptr; + + nItems++; + if (nMaxFiles > 0 && nItems > nMaxFiles) + break; } - else if (nItems >= nAllocatedItems) + } + } + else + { + for (const auto &iter : oFileList) + { + const char *pszFilePath = iter.second->osFilename.c_str(); + if (iter.second->osFilename.size() > nPathLen && + memcmp(pszFilePath, osPath.c_str(), nPathLen) == 0 && + pszFilePath[nPathLen] == '/' && + strstr(pszFilePath + nPathLen + 1, "/") == nullptr) { - nAllocatedItems = nAllocatedItems * 2; - papszDir = static_cast(CPLRealloc( - papszDir, (nAllocatedItems + 2) * sizeof(char *))); + if (nItems == 0) + { + papszDir = + static_cast(CPLCalloc(2, sizeof(char *))); + nAllocatedItems = 1; + } + else if (nItems >= nAllocatedItems) + { + nAllocatedItems = nAllocatedItems * 2; + papszDir = static_cast(CPLRealloc( + papszDir, (nAllocatedItems + 2) * sizeof(char *))); + } + + papszDir[nItems] = CPLStrdup(pszFilePath + nPathLen + 1); + papszDir[nItems + 1] = nullptr; + + nItems++; + if (nMaxFiles > 0 && nItems > nMaxFiles) + break; } - - papszDir[nItems] = CPLStrdup(pszFilePath + nPathLen + 1); - papszDir[nItems + 1] = nullptr; - - nItems++; - if (nMaxFiles > 0 && nItems > nMaxFiles) - break; } } @@ -1184,3 +1343,43 @@ GByte *VSIGetMemFileBuffer(const char *pszFilename, vsi_l_offset *pnDataLength, return pabyData; } + +/************************************************************************/ +/* VSIMemGenerateHiddenFilename() */ +/************************************************************************/ + +/** + * \brief Generates a unique filename that can be used with the /vsimem/ + * virtual file system. + * + * This function returns a (short-lived) string containing a unique filename, + * (using an atomic counter), designed for temporary files that must remain + * invisible for other users working at the "/vsimem/" top-level, i.e. + * such files are not returned by VSIReadDir("/vsimem/") or + * VSIReadDirRecursive("/vsimem/)". + * + * The function does not create the file per se. Such filename can be used to + * create a regular file with VSIFOpenL() or VSIFileFromMemBuffer(), or create + * a directory with VSIMkdir() + * + * Once created, deletion of those files using VSIUnlink(), VSIRmdirRecursive(), + * etc. is of the responsibility of the user. The user should not attempt to + * work with the "parent" directory returned by CPLGetPath() / CPLGetDirname() + * on the returned filename, and work only with files at the same level or + * in subdirectories of what is returned by this function. + * + * @param pszFilename the filename to be appended at the end of the returned + * filename. If not specified, defaults to "unnamed". + * + * @return pointer to a short-lived string (rotating buffer of strings in + * thread-local storage). It is recommended to use CPLStrdup() or std::string() + * immediately on it. + * + * @since GDAL 3.10 + */ +const char *VSIMemGenerateHiddenFilename(const char *pszFilename) +{ + static std::atomic nCounter{0}; + return CPLSPrintf("%s/%u/%s", szHIDDEN_DIRNAME, ++nCounter, + pszFilename ? pszFilename : "unnamed"); +}