diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp index 59e903fbed..255580c720 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ConvertHexGridToSquareGrid.cpp @@ -31,16 +31,6 @@ class Converter , m_SqrYStep(spacingXY.at(1)) { } - ~Converter() noexcept - { - if(m_Valid) - { - for(const auto& atomicFile : m_AtomicFiles) - { - atomicFile->commit(); - } - } - } Converter(const Converter&) = delete; // Copy Constructor Default Implemented Converter(Converter&&) = delete; // Move Constructor Not Implemented @@ -81,7 +71,12 @@ class Converter } std::istringstream headerStream(origHeader, std::ios_base::in | std::ios_base::binary); - m_AtomicFiles.emplace_back(std::make_unique((fs::absolute(m_OutputPath) / (m_FilePrefix + inputPath.filename().string())), false)); + m_AtomicFiles.emplace_back(std::make_unique((fs::absolute(m_OutputPath) / (m_FilePrefix + inputPath.filename().string())))); + auto creationResult = m_AtomicFiles[m_Index]->getResult(); + if(creationResult.invalid()) + { + return creationResult; + } fs::path outPath = m_AtomicFiles[m_Index]->tempFilePath(); // Ensure the output path exists by creating it if necessary @@ -224,6 +219,26 @@ class Converter return {}; } + Result<> commitAllFiles() + { + if(m_Valid) + { + for(const auto& atomicFile : m_AtomicFiles) + { + if(!atomicFile->commit()) + { + return atomicFile->getResult(); + } + } + } + else + { + return MakeErrorResult(-77751, "The files were invalidated during execution, and this point should not be reached without an error result. If this is the sole error please make a bug report by " + "checking the repository at the bottom of this filters documentation!"); + } + return {}; + } + private: const std::atomic_bool& m_ShouldCancel; const fs::path& m_OutputPath; @@ -338,7 +353,9 @@ Result<> ConvertHexGridToSquareGrid::operator()() { if(!m_InputValues->MultiFile) { - return ::Converter(getCancel(), m_InputValues->OutputPath, m_InputValues->OutputFilePrefix, m_InputValues->XYSpacing)(m_InputValues->InputPath); + auto converter = ::Converter(getCancel(), m_InputValues->OutputPath, m_InputValues->OutputFilePrefix, m_InputValues->XYSpacing); + converter(m_InputValues->InputPath); + return converter.commitAllFiles(); } // Now generate all the file names the user is asking for and populate the table @@ -405,5 +422,7 @@ Result<> ConvertHexGridToSquareGrid::operator()() } } + result = MergeResults(converter.commitAllFiles(), result); + return result; } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EbsdToH5Ebsd.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EbsdToH5Ebsd.cpp index 744266b5b6..38a7e2708f 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EbsdToH5Ebsd.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/EbsdToH5Ebsd.cpp @@ -51,12 +51,11 @@ Result<> EbsdToH5Ebsd::operator()() } } - AtomicFile atomicFile(absPath.string(), false); - - auto dirResult = atomicFile.getResult(); - if(dirResult.invalid()) + AtomicFile atomicFile(absPath.string()); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) { - return dirResult; + return creationResult; } // Scope file writer in code block to get around file lock on windows (enforce destructor order) @@ -323,6 +322,9 @@ Result<> EbsdToH5Ebsd::operator()() } } - atomicFile.commit(); + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } return {}; } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDGMTFileFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDGMTFileFilter.cpp index 28a84653bd..42314c83b3 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDGMTFileFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDGMTFileFilter.cpp @@ -124,7 +124,12 @@ IFilter::PreflightResult WriteGBCDGMTFileFilter::preflightImpl(const DataStructu Result<> WriteGBCDGMTFileFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), true); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } WriteGBCDGMTFileInputValues inputValues; @@ -135,7 +140,13 @@ Result<> WriteGBCDGMTFileFilter::executeImpl(DataStructure& dataStructure, const inputValues.CrystalStructuresArrayPath = filterArgs.value(k_CrystalStructuresArrayPath_Key); auto result = WriteGBCDGMTFile(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDTriangleDataFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDTriangleDataFilter.cpp index 0cce8a55dc..9fdf3d0cf2 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDTriangleDataFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteGBCDTriangleDataFilter.cpp @@ -110,7 +110,12 @@ IFilter::PreflightResult WriteGBCDTriangleDataFilter::preflightImpl(const DataSt Result<> WriteGBCDTriangleDataFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), true); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } WriteGBCDTriangleDataInputValues inputValues; @@ -121,7 +126,13 @@ Result<> WriteGBCDTriangleDataFilter::executeImpl(DataStructure& dataStructure, inputValues.FeatureEulerAnglesArrayPath = filterArgs.value(k_FeatureEulerAnglesArrayPath_Key); auto result = WriteGBCDTriangleData(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteINLFileFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteINLFileFilter.cpp index 932eabfb52..228c6c205c 100644 --- a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteINLFileFilter.cpp +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/WriteINLFileFilter.cpp @@ -111,7 +111,12 @@ IFilter::PreflightResult WriteINLFileFilter::preflightImpl(const DataStructure& Result<> WriteINLFileFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), true); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } WriteINLFileInputValues inputValues; @@ -125,7 +130,13 @@ Result<> WriteINLFileFilter::executeImpl(DataStructure& dataStructure, const Arg inputValues.NumFeaturesArrayPath = filterArgs.value(k_NumFeaturesArrayPath_Key); auto result = WriteINLFile(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteAbaqusHexahedron.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteAbaqusHexahedron.cpp index ecaf8c8bbf..72b39b35e3 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteAbaqusHexahedron.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteAbaqusHexahedron.cpp @@ -370,6 +370,15 @@ Result<> WriteAbaqusHexahedron::operator()() fileList.push_back(std::make_unique(m_InputValues->OutputPath.string() + "/" + m_InputValues->FilePrefix + "_elset.inp")); fileList.push_back(std::make_unique(m_InputValues->OutputPath.string() + "/" + m_InputValues->FilePrefix + ".inp")); + for(auto& file : fileList) + { + auto creationResult = file->getResult(); + if(creationResult.invalid()) + { + return creationResult; + } + } + int32 err = writeNodes(this, fileList[0]->tempFilePath().string(), cDims.data(), origin.data(), spacing.data(), getCancel()); // Nodes file if(err < 0) { @@ -432,7 +441,10 @@ Result<> WriteAbaqusHexahedron::operator()() for(auto& file : fileList) { - file->commit(); + if(!file->commit()) + { + return file->getResult(); + } } return {}; diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteStlFile.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteStlFile.cpp index 5aa23517d3..b437e916c4 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteStlFile.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/WriteStlFile.cpp @@ -264,11 +264,11 @@ Result<> WriteStlFile::operator()() if(groupingType == GroupingType::None) { - AtomicFile atomicFile(m_InputValues->OutputStlFile.string(), false); - - if(atomicFile.getResult().invalid()) + AtomicFile atomicFile(m_InputValues->OutputStlFile.string()); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) { - return atomicFile.getResult(); + return creationResult; } { // Scoped to ensure file lock is released and header string is untouched since it is invalid after move @@ -287,7 +287,10 @@ Result<> WriteStlFile::operator()() } } - atomicFile.commit(); + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } return {}; } @@ -319,12 +322,12 @@ Result<> WriteStlFile::operator()() for(const auto featureId : uniqueGrainIds) { // Generate the output file - fileList.push_back( - std::make_unique(m_InputValues->OutputStlDirectory.string() + "/" + m_InputValues->OutputStlPrefix + "Feature_" + StringUtilities::number(featureId) + ".stl", false)); + fileList.push_back(std::make_unique(m_InputValues->OutputStlDirectory.string() + "/" + m_InputValues->OutputStlPrefix + "Feature_" + StringUtilities::number(featureId) + ".stl")); - if(fileList[fileIndex]->getResult().invalid()) + auto creationResult = fileList[fileIndex]->getResult(); + if(creationResult.invalid()) { - return fileList[fileIndex]->getResult(); + return creationResult; } m_MessageHandler(IFilter::Message::Type::Info, fmt::format("Writing STL for Feature Id {}", featureId)); @@ -357,12 +360,12 @@ Result<> WriteStlFile::operator()() { // Generate the output file fileList.push_back(std::make_unique(m_InputValues->OutputStlDirectory.string() + "/" + m_InputValues->OutputStlPrefix + "Ensemble_" + StringUtilities::number(value) + "_" + - "Feature_" + StringUtilities::number(featureId) + ".stl", - false)); + "Feature_" + StringUtilities::number(featureId) + ".stl")); - if(fileList[fileIndex]->getResult().invalid()) + auto creationResult = fileList[fileIndex]->getResult(); + if(creationResult.invalid()) { - return fileList[fileIndex]->getResult(); + return creationResult; } m_MessageHandler(IFilter::Message::Type::Info, fmt::format("Writing STL for Feature Id {}", featureId)); @@ -383,7 +386,10 @@ Result<> WriteStlFile::operator()() for(const auto& atomicFile : fileList) { - atomicFile->commit(); + if(!atomicFile->commit()) + { + return atomicFile->getResult(); + } } return {}; diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ExtractPipelineToFileFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ExtractPipelineToFileFilter.cpp index 519d084388..0b3d2c35fd 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ExtractPipelineToFileFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ExtractPipelineToFileFilter.cpp @@ -129,7 +129,12 @@ Result<> ExtractPipelineToFileFilter::executeImpl(DataStructure& dataStructure, { outputFile.replace_extension(extension); } - AtomicFile atomicFile(outputFile.string(), false); + AtomicFile atomicFile(outputFile.string()); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } { const fs::path exportFilePath = atomicFile.tempFilePath(); std::ofstream fOut(exportFilePath.string(), std::ofstream::out); // test name resolution and create file @@ -140,7 +145,11 @@ Result<> ExtractPipelineToFileFilter::executeImpl(DataStructure& dataStructure, fOut << pipelineJson.dump(2); } - atomicFile.commit(); + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + return {}; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteASCIIDataFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteASCIIDataFilter.cpp index 06153ddb7b..aacf501b72 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteASCIIDataFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteASCIIDataFilter.cpp @@ -174,7 +174,13 @@ Result<> WriteASCIIDataFilter::executeImpl(DataStructure& dataStructure, const A if(static_cast(fileType) == WriteASCIIDataFilter::OutputStyle::SingleFile) { - AtomicFile atomicFile(filterArgs.value(k_OutputPath_Key), false); + AtomicFile atomicFile(filterArgs.value(k_OutputPath_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } + auto outputPath = atomicFile.tempFilePath(); // Make sure any directory path is also available as the user may have just typed // in a path without actually creating the full path @@ -195,7 +201,11 @@ Result<> WriteASCIIDataFilter::executeImpl(DataStructure& dataStructure, const A OStreamUtilities::PrintDataSetsToSingleFile(outStrm, selectedDataArrayPaths, dataStructure, messageHandler, shouldCancel, delimiter, includeIndex, includeHeaders); } - atomicFile.setAutoCommit(true); + + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } } if(static_cast(fileType) == WriteASCIIDataFilter::OutputStyle::MultipleFiles) @@ -211,9 +221,10 @@ Result<> WriteASCIIDataFilter::executeImpl(DataStructure& dataStructure, const A return MakeErrorResult(-11022, fmt::format("Unable to create output directory {}", directoryPath.string())); } } - OStreamUtilities::PrintDataSetsToMultipleFiles(selectedDataArrayPaths, dataStructure, directoryPath.string(), messageHandler, shouldCancel, fileExtension, false, delimiter, includeIndex, - includeHeaders, maxValPerLine); + return OStreamUtilities::PrintDataSetsToMultipleFiles(selectedDataArrayPaths, dataStructure, directoryPath.string(), messageHandler, shouldCancel, fileExtension, false, delimiter, includeIndex, + includeHeaders, maxValPerLine); } + return {}; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoRectilinearCoordinateFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoRectilinearCoordinateFilter.cpp index f1f34be6c1..0477ba4aec 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoRectilinearCoordinateFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoRectilinearCoordinateFilter.cpp @@ -97,7 +97,12 @@ Result<> WriteAvizoRectilinearCoordinateFilter::executeImpl(DataStructure& dataS { AvizoWriterInputValues inputValues; - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), true); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } inputValues.OutputFile = atomicFile.tempFilePath(); inputValues.WriteBinaryFile = filterArgs.value(k_WriteBinaryFile_Key); @@ -106,7 +111,14 @@ Result<> WriteAvizoRectilinearCoordinateFilter::executeImpl(DataStructure& dataS inputValues.Units = filterArgs.value(k_Units_Key); auto result = WriteAvizoRectilinearCoordinate(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } + return result; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoUniformCoordinateFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoUniformCoordinateFilter.cpp index b82e99437d..f617f9cefc 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoUniformCoordinateFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteAvizoUniformCoordinateFilter.cpp @@ -97,7 +97,12 @@ Result<> WriteAvizoUniformCoordinateFilter::executeImpl(DataStructure& dataStruc { AvizoWriterInputValues inputValues; - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), true); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } inputValues.OutputFile = atomicFile.tempFilePath(); inputValues.WriteBinaryFile = filterArgs.value(k_WriteBinaryFile_Key); @@ -106,7 +111,13 @@ Result<> WriteAvizoUniformCoordinateFilter::executeImpl(DataStructure& dataStruc inputValues.Units = filterArgs.value(k_Units_Key); auto result = WriteAvizoUniformCoordinate(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteDREAM3DFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteDREAM3DFilter.cpp index 12e42bc3d0..647065c230 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteDREAM3DFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteDREAM3DFilter.cpp @@ -84,7 +84,12 @@ IFilter::PreflightResult WriteDREAM3DFilter::preflightImpl(const DataStructure& Result<> WriteDREAM3DFilter::executeImpl(DataStructure& dataStructure, const Arguments& args, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(args.value(k_ExportFilePath), false); + AtomicFile atomicFile(args.value(k_ExportFilePath)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } auto exportFilePath = atomicFile.tempFilePath(); auto writeXdmf = args.value(k_WriteXdmf); @@ -105,7 +110,10 @@ Result<> WriteDREAM3DFilter::executeImpl(DataStructure& dataStructure, const Arg auto results = DREAM3D::WriteFile(exportFilePath, dataStructure, pipeline, writeXdmf); if(results.valid()) { - atomicFile.commit(); + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } if(writeXdmf) { fs::path xdmfFilePath = exportFilePath.replace_extension(".xdmf"); diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteFeatureDataCSVFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteFeatureDataCSVFilter.cpp index 282d8667bf..7df80e56b0 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteFeatureDataCSVFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteFeatureDataCSVFilter.cpp @@ -96,6 +96,11 @@ Result<> WriteFeatureDataCSVFilter::executeImpl(DataStructure& dataStructure, co const std::atomic_bool& shouldCancel) const { AtomicFile atomicFile(filterArgs.value(k_FeatureDataFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } auto pOutputFilePath = atomicFile.tempFilePath(); auto pWriteNeighborListDataValue = filterArgs.value(k_WriteNeighborListData_Key); @@ -155,7 +160,10 @@ Result<> WriteFeatureDataCSVFilter::executeImpl(DataStructure& dataStructure, co OStreamUtilities::PrintDataSetsToSingleFile(fout, arrayPaths, dataStructure, messageHandler, shouldCancel, delimiter, true, true, false, "Feature_ID", neighborPaths, pWriteNumFeaturesLineValue); } - atomicFile.commit(); + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } return {}; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteLosAlamosFFTFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteLosAlamosFFTFilter.cpp index 4ddcac6bf6..a6dbc8fd18 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteLosAlamosFFTFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteLosAlamosFFTFilter.cpp @@ -108,7 +108,12 @@ IFilter::PreflightResult WriteLosAlamosFFTFilter::preflightImpl(const DataStruct Result<> WriteLosAlamosFFTFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), true); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } WriteLosAlamosFFTInputValues inputValues; @@ -119,7 +124,13 @@ Result<> WriteLosAlamosFFTFilter::executeImpl(DataStructure& dataStructure, cons inputValues.ImageGeomPath = filterArgs.value(k_ImageGeomPath); auto result = WriteLosAlamosFFT(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkRectilinearGridFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkRectilinearGridFilter.cpp index 013cdc6b58..2ed6be0ff1 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkRectilinearGridFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkRectilinearGridFilter.cpp @@ -113,12 +113,12 @@ IFilter::PreflightResult WriteVtkRectilinearGridFilter::preflightImpl(const Data Result<> WriteVtkRectilinearGridFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), false); + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); - auto dirResult = atomicFile.getResult(); - if(dirResult.invalid()) + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) { - return dirResult; + return creationResult; } WriteVtkRectilinearGridInputValues inputValues; @@ -129,7 +129,13 @@ Result<> WriteVtkRectilinearGridFilter::executeImpl(DataStructure& dataStructure inputValues.SelectedDataArrayPaths = filterArgs.value(k_SelectedDataArrayPaths_Key); auto result = WriteVtkRectilinearGrid(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkStructuredPointsFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkStructuredPointsFilter.cpp index 72d9d8be07..8937684966 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkStructuredPointsFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/WriteVtkStructuredPointsFilter.cpp @@ -113,12 +113,11 @@ IFilter::PreflightResult WriteVtkStructuredPointsFilter::preflightImpl(const Dat Result<> WriteVtkStructuredPointsFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const { - AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key), false); - - auto dirResult = atomicFile.getResult(); - if(dirResult.invalid()) + AtomicFile atomicFile(filterArgs.value(k_OutputFile_Key)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) { - return dirResult; + return creationResult; } WriteVtkStructuredPointsInputValues inputValues; @@ -129,7 +128,13 @@ Result<> WriteVtkStructuredPointsFilter::executeImpl(DataStructure& dataStructur inputValues.SelectedDataArrayPaths = filterArgs.value(k_SelectedDataArrayPaths_Key); auto result = WriteVtkStructuredPoints(dataStructure, messageHandler, shouldCancel, &inputValues)(); - atomicFile.setAutoCommit(result.valid()); + if(result.valid()) + { + if(!atomicFile.commit()) + { + return atomicFile.getResult(); + } + } return result; } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp index 9a228ea4b7..a3a02062e8 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp @@ -170,7 +170,12 @@ inline Result<> WritePythonFilterToPlugin(const std::filesystem::path& pluginPat { std::string content = GeneratePythonFilter(filterName, filterName, Uuid::GenerateV4().str()); fs::path outputPath = pluginPath / fmt::format("{}.py", filterName); - AtomicFile tempFile(outputPath.string(), true); + AtomicFile tempFile(outputPath.string()); + auto creationResult = tempFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } { // Scope this so that the file closes first before we then 'commit' with the atomic file std::ofstream fout(tempFile.tempFilePath(), std::ios_base::out | std::ios_base::binary); @@ -182,6 +187,11 @@ inline Result<> WritePythonFilterToPlugin(const std::filesystem::path& pluginPat fout << content; } + if(!tempFile.commit()) + { + return tempFile.getResult(); + } + return InsertFilterNameInPluginFiles(pluginPath, filterName); } @@ -223,7 +233,12 @@ inline Result<> WritePythonFilterToFile(const std::filesystem::path& outputPath, std::string content = GeneratePythonFilter(filterName, humanName, uuidString); auto outputFilePath = fmt::format("{}{}{}.py", outputPath.string(), std::string{std::filesystem::path::preferred_separator}, filterName); - AtomicFile tempFile(outputFilePath, true); + AtomicFile tempFile(outputFilePath); + auto creationResult = tempFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } { // Scope this so that the file closes first before we then 'commit' with the atomic file std::ofstream fout(tempFile.tempFilePath(), std::ios_base::out | std::ios_base::binary); @@ -235,6 +250,11 @@ inline Result<> WritePythonFilterToFile(const std::filesystem::path& outputPath, fout << content; } + if(!tempFile.commit()) + { + return tempFile.getResult(); + } + return {}; } @@ -292,7 +312,12 @@ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirect } auto outputPath = pluginRootPath / "Plugin.py"; { - AtomicFile tempFile(outputPath.string(), true); + AtomicFile tempFile(outputPath.string()); + auto creationResult = tempFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } { // Scope this so that the file closes first before we then 'commit' with the atomic file std::ofstream fout(tempFile.tempFilePath(), std::ios_base::out | std::ios_base::binary); @@ -305,6 +330,10 @@ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirect fout << content; } + if(!tempFile.commit()) + { + return tempFile.getResult(); + } } if(createBatchShellScript) @@ -314,7 +343,12 @@ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirect #else outputPath = pluginRootPath / "init_evn.sh"; #endif - AtomicFile initTempFile(outputPath.string(), true); + AtomicFile initTempFile(outputPath.string()); + auto creationResult = initTempFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } { // Scope this so that the file closes first before we then 'commit' with the atomic file std::ofstream fout(initTempFile.tempFilePath(), std::ios_base::out | std::ios_base::binary); @@ -330,12 +364,21 @@ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirect fout << content; } + if(!initTempFile.commit()) + { + return initTempFile.getResult(); + } } // Write the __init__.py file outputPath = pluginRootPath / "__init__.py"; { - AtomicFile initTempFile(outputPath.string(), true); + AtomicFile initTempFile(outputPath.string()); + auto creationResult = initTempFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } { // Scope this so that the file closes first before we then 'commit' with the atomic file std::ofstream fout(initTempFile.tempFilePath(), std::ios_base::out | std::ios_base::binary); @@ -370,6 +413,10 @@ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirect fout << content; } + if(!initTempFile.commit()) + { + return initTempFile.getResult(); + } } // Now loop over each Filter and generate the skeleton files auto filterList = StringUtilities::split(pluginFilterList, ','); diff --git a/src/simplnx/Common/AtomicFile.cpp b/src/simplnx/Common/AtomicFile.cpp index f878f65dea..59365adf1b 100644 --- a/src/simplnx/Common/AtomicFile.cpp +++ b/src/simplnx/Common/AtomicFile.cpp @@ -1,5 +1,6 @@ #include "AtomicFile.hpp" +#include "simplnx/Utilities/FileUtilities.hpp" #include "simplnx/Utilities/FilterUtilities.hpp" #include @@ -26,28 +27,22 @@ std::string randomDirName() } } // namespace -AtomicFile::AtomicFile(const std::string& filename, bool autoCommit) +AtomicFile::AtomicFile(const std::string& filename) : m_FilePath(fs::path(filename)) -, m_AutoCommit(autoCommit) +, m_Result({}) { - m_TempFilePath = fs::path(fmt::format("{}/{}/{}", m_FilePath.parent_path().string(), ::randomDirName(), m_FilePath.filename().string())); - m_Result = createOutputDirectories(); + initialize(); } -AtomicFile::AtomicFile(fs::path&& filepath, bool autoCommit) +AtomicFile::AtomicFile(fs::path&& filepath) : m_FilePath(std::move(filepath)) -, m_AutoCommit(autoCommit) +, m_Result({}) { - m_TempFilePath = fs::path(fmt::format("{}/{}/{}", m_FilePath.parent_path().string(), ::randomDirName(), m_FilePath.filename().string())); - m_Result = createOutputDirectories(); + initialize(); } AtomicFile::~AtomicFile() { - if(m_AutoCommit) - { - commit(); - } if(fs::exists(m_TempFilePath) || fs::exists(m_TempFilePath.parent_path())) { removeTempFile(); @@ -59,24 +54,24 @@ fs::path AtomicFile::tempFilePath() const return m_TempFilePath; } -void AtomicFile::commit() const +bool AtomicFile::commit() { if(!fs::exists(m_TempFilePath)) { - throw std::runtime_error(m_TempFilePath.string() + " does not exist"); + updateResult(MakeErrorResult(-15780, m_TempFilePath.string() + " does not exist")); + return false; } - fs::rename(m_TempFilePath, m_FilePath); -} - -void AtomicFile::setAutoCommit(bool value) -{ - m_AutoCommit = value; -} + try + { + fs::rename(m_TempFilePath, m_FilePath); + } catch(const std::filesystem::filesystem_error& error) + { + updateResult(MakeErrorResult(-15780, fmt::format("When attempting to move the temp file to the end absolute path, AtomicFile encountered the following error on rename(): '{}'", error.what()))); + return false; + } -bool AtomicFile::getAutoCommit() const -{ - return m_AutoCommit; + return true; } void AtomicFile::removeTempFile() const @@ -95,3 +90,46 @@ Result<> AtomicFile::createOutputDirectories() // in a path without actually creating the full path return CreateOutputDirectories(m_TempFilePath.parent_path()); } + +void AtomicFile::clearResult() +{ + m_Result = {}; +} + +void AtomicFile::updateResult(Result<>&& result) +{ + m_Result = MergeResults(m_Result, result); +} + +void AtomicFile::initialize() +{ + // If the path is relative, then make it absolute + if(!m_FilePath.is_absolute()) + { + try + { + m_FilePath = fs::absolute(m_FilePath); + } catch(const std::filesystem::filesystem_error& error) + { + updateResult(MakeErrorResult(-15780, fmt::format("When attempting to create an absolute path, AtomicFile encountered the following error: '{}'", error.what()))); + } + } + + // Validate write permissions + { // Scope to avoid accessing result after it's no longer guaranteed by the move + auto result = FileUtilities::ValidateDirectoryWritePermission(m_FilePath, true); + if(result.invalid()) + { + updateResult(std::move(result)); + } + } + + m_TempFilePath = fs::path(fmt::format("{}/{}/{}", m_FilePath.parent_path().string(), ::randomDirName(), m_FilePath.filename().string())); + { // Scope to avoid accessing result after it's no longer guaranteed by the move + auto result = createOutputDirectories(); + if(result.invalid()) + { + updateResult(std::move(result)); + } + } +} diff --git a/src/simplnx/Common/AtomicFile.hpp b/src/simplnx/Common/AtomicFile.hpp index cb025d168e..4e05908f35 100644 --- a/src/simplnx/Common/AtomicFile.hpp +++ b/src/simplnx/Common/AtomicFile.hpp @@ -16,30 +16,57 @@ namespace fs = std::filesystem; * @brief The AtomicFile class accepts a filepath which it stores and * used to create a temporary file. This temporary can be written to in place * of the original file path. Upon commit() the temporary file will be moved to - * the end location passed in originally. By enabling autoCommit the temporary file - * will be swapped upon object destruction. The temporary file will always be deleted + * the end location passed in originally. The temporary file will always be deleted * upon object destruction. */ class SIMPLNX_EXPORT AtomicFile { public: - explicit AtomicFile(const std::string& filename, bool autoCommit = false); - explicit AtomicFile(fs::path&& filename, bool autoCommit = false); + /** + * @brief Constructs the object and stores errors !!!CHECK getResult()!!! + */ + explicit AtomicFile(const std::string& filename); + /** + * @brief Constructs the object and stores errors !!!CHECK getResult()!!! + */ + explicit AtomicFile(fs::path&& filename); ~AtomicFile(); - fs::path tempFilePath() const; - void commit() const; - void setAutoCommit(bool value); - bool getAutoCommit() const; + /** + * @brief Fetches the file path object to work from + * @return fs::path the working file path modifications should be made to + */ + [[nodiscard]] fs::path tempFilePath() const; + + /** + * @brief Attempts to move the temp file to its final path !!!CHECK getResult() IF FALSE!!! + * @return bool - if false you MUST call getResult() to error codes + */ + [[nodiscard]] bool commit(); + + /** + * @brief Purges the temporary file + */ void removeTempFile() const; - Result<> getResult() const; + + /** + * @brief Fetch for amalgamated error codes !!!call clearResult() To Reset Errors/Warnings!!! + * @return Result<> The result object containing all collected errors + */ + [[nodiscard]] Result<> getResult() const; + + /** + * @brief Empties the result container + */ + void clearResult(); private: + void updateResult(Result<>&& result); + void initialize(); fs::path m_FilePath; fs::path m_TempFilePath; - bool m_AutoCommit = false; - Result<> m_Result = {}; + Result<> m_Result; Result<> createOutputDirectories(); }; diff --git a/src/simplnx/Parameters/FileSystemPathParameter.cpp b/src/simplnx/Parameters/FileSystemPathParameter.cpp index 522c01e259..8ddbbaa4c9 100644 --- a/src/simplnx/Parameters/FileSystemPathParameter.cpp +++ b/src/simplnx/Parameters/FileSystemPathParameter.cpp @@ -2,6 +2,7 @@ #include "simplnx/Common/Any.hpp" #include "simplnx/Common/StringLiteral.hpp" +#include "simplnx/Utilities/FileUtilities.hpp" #include "simplnx/Utilities/StringUtilities.hpp" #include @@ -13,35 +14,12 @@ #include #include -#ifdef _WIN32 -#include -#define FSPP_ACCESS_FUNC_NAME _access -#else -#include -#define FSPP_ACCESS_FUNC_NAME access -#endif - namespace fs = std::filesystem; using namespace nx::core; namespace { -#ifdef _WIN32 -constexpr int k_CheckWritable = 2; -#else -constexpr int k_CheckWritable = W_OK; -#endif - -constexpr StringLiteral k_PathKey = "path"; -constexpr int k_HasAccess = 0; - -//----------------------------------------------------------------------------- -bool HasWriteAccess(const std::string& path) -{ - return FSPP_ACCESS_FUNC_NAME(path.c_str(), k_CheckWritable) == k_HasAccess; -} - //----------------------------------------------------------------------------- Result<> ValidateInputFile(const FileSystemPathParameter::ValueType& path) { @@ -70,70 +48,11 @@ Result<> ValidateInputDir(const FileSystemPathParameter::ValueType& path) } return {}; } -//----------------------------------------------------------------------------- -Result<> ValidateDirectoryWritePermission(const FileSystemPathParameter::ValueType& path, bool isFile) -{ - if(path.empty()) - { - return MakeErrorResult(-16, "ValidateDirectoryWritePermission() error: given path was empty."); - } - - auto checkedPath = path; - if(isFile) - { - checkedPath = checkedPath.parent_path(); - } - // We now have the parent directory. Let us see if *any* part of the path exists - - // If the path is relative, then make it absolute - if(!checkedPath.is_absolute()) - { - try - { - checkedPath = fs::absolute(checkedPath); - } catch(const std::filesystem::filesystem_error& error) - { - return MakeErrorResult(-15, fmt::format("ValidateDirectoryWritePermission() threw an error: '{}'", error.what())); - } - } - - auto rootPath = checkedPath.root_path(); - - // The idea here is to start walking up from the deepest directory and hopefully - // find an existing directory. If we get to the top if the path and we are still - // empty then: - // On unix based systems not sure if it would happen. Even if the user set a path - // to another drive that didn't exist, at some point you hit the '/' and then you - // can try to create the directories. - // On Windows the user put in a bogus drive letter which is just a hard failure - // because we can't make up a new drive letter. - while(!fs::exists(checkedPath) && checkedPath != rootPath) - { - checkedPath = checkedPath.parent_path(); - } - - if(checkedPath.empty()) - { - return MakeErrorResult(-19, "ValidateDirectoryWritePermission() resolved path was empty"); - } - - if(!fs::exists(checkedPath)) - { - return MakeErrorResult(-11, fmt::format("ValidateDirectoryWritePermission() error: The drive does not exist on this system: '{}'", checkedPath.string())); - } - - // We should be at the top of the tree with an existing directory. - if(HasWriteAccess(checkedPath.string())) - { - return {}; - } - return MakeErrorResult(-8, fmt::format("User does not have write permissions to path '{}'", path.string())); -} //----------------------------------------------------------------------------- Result<> ValidateOutputFile(const FileSystemPathParameter::ValueType& path) { - auto result = ValidateDirectoryWritePermission(path, true); + auto result = FileUtilities::ValidateDirectoryWritePermission(path, true); if(result.invalid()) { return result; @@ -148,7 +67,7 @@ Result<> ValidateOutputFile(const FileSystemPathParameter::ValueType& path) //----------------------------------------------------------------------------- Result<> ValidateOutputDir(const FileSystemPathParameter::ValueType& path) { - auto result = ValidateDirectoryWritePermission(path, false); + auto result = FileUtilities::ValidateDirectoryWritePermission(path, false); if(result.invalid()) { return result; diff --git a/src/simplnx/Utilities/FileUtilities.cpp b/src/simplnx/Utilities/FileUtilities.cpp index 4161956ce5..988df77167 100644 --- a/src/simplnx/Utilities/FileUtilities.cpp +++ b/src/simplnx/Utilities/FileUtilities.cpp @@ -5,11 +5,29 @@ #include #include +#ifdef _WIN32 +#include +#define FSPP_ACCESS_FUNC_NAME _access +#else +#include +#define FSPP_ACCESS_FUNC_NAME access +#endif + namespace fs = std::filesystem; -namespace nx::core::FileUtilities +namespace { +#ifdef _WIN32 +constexpr int k_CheckWritable = 2; +#else +constexpr int k_CheckWritable = W_OK; +#endif + +constexpr int k_HasAccess = 0; +}; // namespace +namespace nx::core::FileUtilities +{ int64 LinesInFile(const std::string& filepath) { const usize BUFFER_SIZE = 16384; @@ -139,4 +157,69 @@ Result<> ValidateCSVFile(const std::string& filePath) return {}; } +//----------------------------------------------------------------------------- +bool HasWriteAccess(const std::string& path) +{ + return FSPP_ACCESS_FUNC_NAME(path.c_str(), k_CheckWritable) == k_HasAccess; +} + +//----------------------------------------------------------------------------- +Result<> ValidateDirectoryWritePermission(const fs::path& path, bool isFile) +{ + if(path.empty()) + { + return MakeErrorResult(-16, "ValidateDirectoryWritePermission() error: given path was empty."); + } + + auto checkedPath = path; + if(isFile) + { + checkedPath = checkedPath.parent_path(); + } + // We now have the parent directory. Let us see if *any* part of the path exists + + // If the path is relative, then make it absolute + if(!checkedPath.is_absolute()) + { + try + { + checkedPath = fs::absolute(checkedPath); + } catch(const std::filesystem::filesystem_error& error) + { + return MakeErrorResult(-15, fmt::format("ValidateDirectoryWritePermission() threw an error: '{}'", error.what())); + } + } + + auto rootPath = checkedPath.root_path(); + + // The idea here is to start walking up from the deepest directory and hopefully + // find an existing directory. If we get to the top if the path and we are still + // empty then: + // On unix based systems not sure if it would happen. Even if the user set a path + // to another drive that didn't exist, at some point you hit the '/' and then you + // can try to create the directories. + // On Windows the user put in a bogus drive letter which is just a hard failure + // because we can't make up a new drive letter. + while(!fs::exists(checkedPath) && checkedPath != rootPath) + { + checkedPath = checkedPath.parent_path(); + } + + if(checkedPath.empty()) + { + return MakeErrorResult(-19, "ValidateDirectoryWritePermission() resolved path was empty"); + } + + if(!fs::exists(checkedPath)) + { + return MakeErrorResult(-11, fmt::format("ValidateDirectoryWritePermission() error: The drive does not exist on this system: '{}'", checkedPath.string())); + } + + // We should be at the top of the tree with an existing directory. + if(HasWriteAccess(checkedPath.string())) + { + return {}; + } + return MakeErrorResult(-8, fmt::format("User does not have write permissions to path '{}'", path.string())); +} } // namespace nx::core::FileUtilities diff --git a/src/simplnx/Utilities/FileUtilities.hpp b/src/simplnx/Utilities/FileUtilities.hpp index 60a7c3133c..33e9f97c0b 100644 --- a/src/simplnx/Utilities/FileUtilities.hpp +++ b/src/simplnx/Utilities/FileUtilities.hpp @@ -31,13 +31,14 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #pragma once +#include "simplnx/Common/Result.hpp" + +#include #include -#include "simplnx/Common/Result.hpp" +namespace fs = std::filesystem; -namespace nx::core -{ -namespace FileUtilities +namespace nx::core::FileUtilities { /** @@ -53,5 +54,18 @@ SIMPLNX_EXPORT int64 LinesInFile(const std::string& filepath); * @return */ SIMPLNX_EXPORT Result<> ValidateCSVFile(const std::string& filePath); -} // namespace FileUtilities -} // namespace nx::core + +/** + * @brief + * @param filePath + * @return + */ +SIMPLNX_EXPORT bool HasWriteAccess(const std::string& path); + +/** + * @brief + * @param filePath + * @return + */ +SIMPLNX_EXPORT Result<> ValidateDirectoryWritePermission(const fs::path& path, bool isFile); +} // namespace nx::core::FileUtilities diff --git a/src/simplnx/Utilities/OStreamUtilities.cpp b/src/simplnx/Utilities/OStreamUtilities.cpp index e159687db5..c94d1e89e8 100644 --- a/src/simplnx/Utilities/OStreamUtilities.cpp +++ b/src/simplnx/Utilities/OStreamUtilities.cpp @@ -375,9 +375,9 @@ std::string DelimiterToString(uint64 delim) * @param includeHeaders The boolean that determines if headers are printed | leave blank if binary is end output * @param componentsPerLine The amount of elements to be inserted before newline character | leave blank if binary is end output */ -void PrintDataSetsToMultipleFiles(const std::vector& objectPaths, DataStructure& dataStructure, const std::string& directoryPath, const IFilter::MessageHandler& mesgHandler, - const std::atomic_bool& shouldCancel, const std::string& fileExtension, bool exportToBinary, const std::string& delimiter, bool includeIndex, bool includeHeaders, - size_t componentsPerLine) +Result<> PrintDataSetsToMultipleFiles(const std::vector& objectPaths, DataStructure& dataStructure, const std::string& directoryPath, const IFilter::MessageHandler& mesgHandler, + const std::atomic_bool& shouldCancel, const std::string& fileExtension, bool exportToBinary, const std::string& delimiter, bool includeIndex, bool includeHeaders, + size_t componentsPerLine) { fs::path dirPath(directoryPath); if(!fs::is_directory(dirPath)) @@ -387,7 +387,12 @@ void PrintDataSetsToMultipleFiles(const std::vector& objectPaths, Data for(const auto& dataPath : objectPaths) { - AtomicFile atomicFile(fmt::format("{}/{}{}", directoryPath, dataPath.getTargetName(), fileExtension), false); + AtomicFile atomicFile(fmt::format("{}/{}{}", directoryPath, dataPath.getTargetName(), fileExtension)); + auto creationResult = atomicFile.getResult(); + if(creationResult.invalid()) + { + return creationResult; + } auto outputFilePath = atomicFile.tempFilePath().string(); mesgHandler(IFilter::Message::Type::Info, fmt::format("Writing IArray ({}) to output file {}", dataPath.getTargetName(), outputFilePath)); @@ -431,11 +436,16 @@ void PrintDataSetsToMultipleFiles(const std::vector& objectPaths, Data } if(shouldCancel) { - return; + return {}; + } + if(!atomicFile.commit()) + { + return atomicFile.getResult(); } - atomicFile.commit(); } -}; + + return {}; +} /** * @brief [Single Output][Custom OStream] | Writes one IArray child to some OStream diff --git a/src/simplnx/Utilities/OStreamUtilities.hpp b/src/simplnx/Utilities/OStreamUtilities.hpp index aed38147a3..dbe89c176d 100644 --- a/src/simplnx/Utilities/OStreamUtilities.hpp +++ b/src/simplnx/Utilities/OStreamUtilities.hpp @@ -10,9 +10,7 @@ #include "simplnx/DataStructure/StringArray.hpp" #include "simplnx/Filter/IFilter.hpp" -namespace nx::core -{ -namespace OStreamUtilities +namespace nx::core::OStreamUtilities { /** * @brief enum for accepted output delimiters in DREAM3D @@ -47,9 +45,10 @@ SIMPLNX_EXPORT std::string DelimiterToString(uint64 delim); * @param includeHeaders The boolean that determines if headers are printed | leave blank if binary is end output * @param componentsPerLine The amount of elements to be inserted before newline character | leave blank if binary is end output */ -SIMPLNX_EXPORT void PrintDataSetsToMultipleFiles(const std::vector& objectPaths, DataStructure& dataStructure, const std::string& directoryPath, const IFilter::MessageHandler& mesgHandler, - const std::atomic_bool& shouldCancel, const std::string& fileExtension = ".txt", bool exportToBinary = false, const std::string& delimiter = "", - bool includeIndex = false, bool includeHeaders = false, size_t componentsPerLine = 0); +SIMPLNX_EXPORT Result<> PrintDataSetsToMultipleFiles(const std::vector& objectPaths, DataStructure& dataStructure, const std::string& directoryPath, + const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, const std::string& fileExtension = ".txt", + bool exportToBinary = false, const std::string& delimiter = "", bool includeIndex = false, bool includeHeaders = false, + size_t componentsPerLine = 0); /** * @brief [Single Output][Custom OStream] | Writes one IArray child to some OStream @@ -85,6 +84,4 @@ SIMPLNX_EXPORT void PrintSingleDataObject(std::ostream& outputStrm, const DataPa SIMPLNX_EXPORT void PrintDataSetsToSingleFile(std::ostream& outputStrm, const std::vector& objectPaths, DataStructure& dataStructure, const IFilter::MessageHandler& mesgHandler, const std::atomic_bool& shouldCancel, const std::string& delimiter = "", bool includeIndex = false, bool includeHeaders = false, bool writeFirstIndex = true, const std::string& indexName = "Index", const std::vector& neighborLists = {}, bool writeNumOfFeatures = false); -} // namespace OStreamUtilities - -} // namespace nx::core +} // namespace nx::core::OStreamUtilities