diff --git a/ReleaseNotes.md b/ReleaseNotes.md index db60caae162dcde8258331223ac58b792fcbc207..672c15c97d3d56b65f56716e350129f122ce7765 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -6,6 +6,7 @@ - cta/CTA#641 - Archive workflow of Postgres Scheduler DB can write a file to tape - cta/CTA#257 - Allow CTA CI runner to use MHVTL ULTRIUM config - cta/CTA#667 - Sonarcloud code smells in catalogue +- cta/CTA#670 - Add the ability to read EnstoreLarge tapes ### Bug Fixes - cta/CTA#485 - Check disk file metadata on delete requests diff --git a/common/dataStructures/LabelFormat.hpp b/common/dataStructures/LabelFormat.hpp index 36dbb5c81eb531be26a4f3fe433847533b95629e..6744d0cd4d5dbd0dcf409b248dbc5d394ef97125 100644 --- a/common/dataStructures/LabelFormat.hpp +++ b/common/dataStructures/LabelFormat.hpp @@ -30,7 +30,8 @@ struct Label { enum class Format : std::uint8_t { CTA = 0x00, OSM = 0x01, - Enstore = 0x02 + Enstore = 0x02, + EnstoreLarge = 0x03 }; static Format validateFormat(const std::optional<std::uint8_t>& ouiFormat, const std::string& strContext) { @@ -43,6 +44,7 @@ struct Label { case Format::CTA: case Format::OSM: case Format::Enstore: + case Format::EnstoreLarge: return format; default: { diff --git a/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt index 7b54085692b04fbc5ed017413724c1e668dad5ef..a4a6c5cb7e3e58352f5cb1354bcf09a1d985aef3 100644 --- a/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt +++ b/tapeserver/castor/tape/tapeserver/file/CMakeLists.txt @@ -35,6 +35,8 @@ set(TAPESERVER_FILE_LIBRARY_SRCS OsmReadSession.cpp EnstoreFileReader.cpp EnstoreReadSession.cpp + EnstoreLargeFileReader.cpp + EnstoreLargeReadSession.cpp OsmFileStructure.cpp CpioFileHeaderStructure.cpp ReadSession.cpp diff --git a/tapeserver/castor/tape/tapeserver/file/EnstoreLargeFileReader.cpp b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeFileReader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fed4472c7f0925529c375cb050344c4e8b4ac2fe --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeFileReader.cpp @@ -0,0 +1,193 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <limits> +#include <memory> +#include <sstream> +#include <string> + +#include "castor/tape/tapeserver/drive/DriveInterface.hpp" +#include "castor/tape/tapeserver/file/CtaReadSession.hpp" +#include "castor/tape/tapeserver/file/EnstoreLargeFileReader.hpp" +#include "castor/tape/tapeserver/file/HeaderChecker.hpp" +#include "castor/tape/tapeserver/file/Structures.hpp" +#include "scheduler/RetrieveJob.hpp" + +namespace castor::tape::tapeFile { + +EnstoreLargeFileReader::EnstoreLargeFileReader(ReadSession& rs, const cta::RetrieveJob& fileToRecall) : +FileReader(rs, fileToRecall) { + setPositioningMethod(cta::PositioningMethod::ByFSeq); // Enstore did not store block IDs +} + +void EnstoreLargeFileReader::setPositioningMethod(const cta::PositioningMethod& newMethod) { + m_positionCommandCode = newMethod; +} + +void EnstoreLargeFileReader::positionByFseq(const cta::RetrieveJob& fileToRecall) { + if (m_session.getCurrentFilePart() != PartOfFile::Header) { + m_session.setCorrupted(); + throw SessionCorrupted(); + } + // Make sure the session state is advanced to cover our failures + // and allow next call to position to discover we failed half way + m_session.setCurrentFilePart(PartOfFile::HeaderProcessing); + + if (fileToRecall.selectedTapeFile().fSeq < 1) { + std::ostringstream err; + err << std::string(__FUNCTION__) << ": " + << "Unexpected fileId. fSeq expected >=1, got: " << fileToRecall.selectedTapeFile().fSeq << ")"; + throw cta::exception::InvalidArgument(err.str()); + } + + const int64_t fSeq_delta = + static_cast<int64_t>(fileToRecall.selectedTapeFile().fSeq) - static_cast<int64_t>(m_session.getCurrentFseq()); + moveReaderByFSeqDelta(fSeq_delta); // Let's just try this + checkHeaders(fileToRecall); +} + +void EnstoreLargeFileReader::positionByBlockID(const cta::RetrieveJob& fileToRecall) { + throw NotImplemented( + "EnstoreLargeFileReader::positionByBlockID() Cannot be implemented. Enstore did not store block IDs"); +} + +void EnstoreLargeFileReader::setBlockSize(const UHL1& uhl1) { // Could inherit + m_currentBlockSize = static_cast<size_t>(atol(uhl1.getBlockSize().c_str())); + if (m_currentBlockSize < 1) { + std::ostringstream ex_str; + ex_str << std::string(__FUNCTION__) << ": " + << "Invalid block size in uhl1 detected"; + throw TapeFormatError(ex_str.str()); + } +} + +size_t EnstoreLargeFileReader::readNextDataBlock(void* data, const size_t size) { + if (size != m_currentBlockSize) { + throw WrongBlockSize(); + } + size_t bytes_read = m_session.m_drive.readBlock(data, size); + // end of file reached! we will keep on reading until we have read the file mark at the end of the trailers + if (!bytes_read) { + checkTrailers(); + // the following is a normal day exception: end of files exceptions are thrown at the end of each file being read + throw EndOfFile(); + } + return bytes_read; +} + +void EnstoreLargeFileReader::moveToFirstHeaderBlock() { + throw NotImplemented("EnstoreLargeFileReader::moveToFirstHeaderBlock() Not implemented."); +} + +void EnstoreLargeFileReader::moveReaderByFSeqDelta(const int64_t fSeq_delta) { + if (fSeq_delta == 0) { + // do nothing we are in the correct place + } + else if (fSeq_delta > 0) { + // we need to skip three file marks per file (header, payload, trailer) + m_session.m_drive.spaceFileMarksForward(static_cast<uint32_t>(fSeq_delta) * 3); + } + else { // fSeq_delta < 0 + // we need to skip three file marks per file + // (trailer, payload, header) + 1 to go on the BOT (beginning of tape) side + // of the file mark before the header of the file we want to read + m_session.m_drive.spaceFileMarksBackwards(static_cast<uint32_t>(std::abs(fSeq_delta)) * 3 + 1); + m_session.m_drive.readFileMark(std::string(__FUNCTION__) + ": " + + "Reading file mark right before the header of the file we want to read"); + } +} + +void EnstoreLargeFileReader::checkTrailers() { + m_session.setCurrentFilePart(PartOfFile::Trailer); + + // let's read and check the trailers + + size_t blockSize = 256 * 1024; + char* data = new char[blockSize + 1]; + size_t bytes_read = m_session.m_drive.readBlock(data, blockSize); + + EOF1 eof1; + EOF2 eof2; + UTL1 utl1; + + if (bytes_read < sizeof(eof1) + sizeof(eof2) + sizeof(utl1)) { + throw cta::exception::Exception(std::string(__FUNCTION__) + + " failed: Too few bytes read for headers:" + std::to_string(bytes_read)); + } + memcpy(&eof1, data, sizeof(eof1)); + memcpy(&eof2, data + sizeof(eof1), sizeof(eof2)); + memcpy(&utl1, data + sizeof(eof1) + sizeof(eof2), sizeof(utl1)); + delete[] data; + + m_session.m_drive.readFileMark(std::string(__FUNCTION__) + ": " + "Reading file mark at the end of file header"); + + m_session.setCurrentFseq(m_session.getCurrentFseq() + 1); // moving on to the header of the next file + m_session.setCurrentFilePart(PartOfFile::Header); + + // the size of the headers is fine, now let's check each header + try { + eof1.verify(true); // Skip certain field where enstore and CTA don't match + eof2.verify("D"); + utl1.verify(); + } + catch (std::exception& e) { + throw TapeFormatError(e.what()); + } +} + +void EnstoreLargeFileReader::checkHeaders(const cta::RetrieveJob& fileToRecall) { + // save the current fSeq into the read session + m_session.setCurrentFseq(fileToRecall.selectedTapeFile().fSeq); + + size_t blockSize = 256 * 1024; + char* data = new char[blockSize + 1]; + size_t bytes_read = m_session.m_drive.readBlock(data, blockSize); + + HDR1 hdr1; + HDR2 hdr2; + UHL1 uhl1; + + if (bytes_read < sizeof(hdr1) + sizeof(hdr2) + sizeof(uhl1)) { + throw cta::exception::Exception(std::string(__FUNCTION__) + + " failed: Too few bytes read for headers:" + std::to_string(bytes_read)); + } + memcpy(&hdr1, data, sizeof(hdr1)); + memcpy(&hdr2, data + sizeof(hdr1), sizeof(hdr1)); + memcpy(&uhl1, data + sizeof(hdr1) + sizeof(hdr2), sizeof(uhl1)); + delete[] data; + + m_session.m_drive.readFileMark(std::string(__FUNCTION__) + ": " + "Reading file mark at the end of file header"); + // after this we should be where we want, i.e. at the beginning of the file + m_session.setCurrentFilePart(PartOfFile::Payload); + + // the size of the headers is fine, now let's check each header + // Extend these with skipped things for Fermilab tapes + try { + hdr1.verify(true); // Skip certain field where enstore and CTA don't match + hdr2.verify("D"); + uhl1.verify(); + } + catch (std::exception& e) { + throw TapeFormatError(e.what()); + } + + // This differs from CTA checkHeaders in that none of the checks in checkHDR1 or checkUHL1 + // works for these Enstore tapes. We skip this entirely but get the block size out of UHL1 + setBlockSize(uhl1); +} + +} // namespace castor::tape::tapeFile diff --git a/tapeserver/castor/tape/tapeserver/file/EnstoreLargeFileReader.hpp b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeFileReader.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e81ca883eca3be31bf3e1f2e940cb062bb5dea70 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeFileReader.hpp @@ -0,0 +1,62 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <fstream> +#include <memory> + +#include "castor/tape/tapeserver/file/CpioFileHeaderStructure.hpp" +#include "castor/tape/tapeserver/file/FileReader.hpp" + +namespace castor::tape::tapeFile { + +class UHL1; + +class EnstoreLargeFileReader : public FileReader { +public: + CTA_GENERATE_EXCEPTION_CLASS(NotImplemented); + + /** + * Constructor + * + * It will bind itself to an existing read session and position the tape right at the beginning of the file + * + * @param rs session to bind to + * @param fileToRecall the file which will be recalled + */ + EnstoreLargeFileReader(ReadSession& rs, const cta::RetrieveJob& fileToRecall); + + /** + * Destructor of the FileReader. It will release the lock on the read session. + */ + ~EnstoreLargeFileReader() override = default; + + size_t readNextDataBlock(void* data, const size_t size) override; + +private: + void setPositioningMethod(const cta::PositioningMethod& newMethod); + void positionByFseq(const cta::RetrieveJob& fileToRecall) override; + void positionByBlockID(const cta::RetrieveJob& fileToRecall) override; + void setBlockSize(const UHL1& uhl1); + void moveToFirstHeaderBlock(); // Not implemented + void moveReaderByFSeqDelta(const int64_t fSeq_delta); + void checkHeaders(const cta::RetrieveJob& fileToRecall); + void checkTrailers(); +}; + +} // namespace castor::tape::tapeFile diff --git a/tapeserver/castor/tape/tapeserver/file/EnstoreLargeReadSession.cpp b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeReadSession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f15ecf36cab6d90064b5d2a67ed4c1baeb45a132 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeReadSession.cpp @@ -0,0 +1,65 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "castor/tape/tapeserver/file/Exceptions.hpp" +#include "castor/tape/tapeserver/file/HeaderChecker.hpp" +#include "castor/tape/tapeserver/file/EnstoreLargeReadSession.hpp" +#include "castor/tape/tapeserver/file/Structures.hpp" +#include "common/exception/Exception.hpp" + +namespace castor::tape::tapeFile { + +EnstoreLargeReadSession::EnstoreLargeReadSession(tapeserver::drive::DriveInterface& drive, + const tapeserver::daemon::VolumeInfo& volInfo, + const bool useLbp) : +ReadSession(drive, volInfo, useLbp) { + m_drive.rewind(); + m_drive.disableLogicalBlockProtection(); + m_detectedLbp = false; + + VOL1 vol1; + + // VOL1 on the EnstoreLarge tapes is longer than the existing ones. + // Throw away the end and validate the beggining as a normal VOL1 + size_t blockSize = 256 * 1024; + char* data = new char[blockSize + 1]; + size_t bytes_read = m_drive.readBlock(data, blockSize); + if (bytes_read < sizeof(vol1)) { + throw cta::exception::Exception(std::string(__FUNCTION__) + " failed: Too few bytes read from label"); + } + memcpy(&vol1, data, sizeof(vol1)); + delete[] data; + + // Tapes should have label character 3, but if they were recycled from CPIO tapes, it could be 0 + try { + vol1.verify("3"); + } catch (std::exception& e) { + try { + vol1.verify("0"); + } catch (std::exception& e) { + throw TapeFormatError(e.what()); + }; + }; + HeaderChecker::checkVOL1(vol1, volInfo.vid); + // after which we are at the end of VOL1 header (e.g. beginning of first file) + m_drive.readFileMark(std::string(__FUNCTION__) + " failed: Reading filemark"); +} + +} // namespace castor::tape::tapeFile diff --git a/tapeserver/castor/tape/tapeserver/file/EnstoreLargeReadSession.hpp b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeReadSession.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ea85cdc75ae17bf31e7bd43c66b6ed33b59e28ac --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/file/EnstoreLargeReadSession.hpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "castor/tape/tapeserver/daemon/VolumeInfo.hpp" +#include "castor/tape/tapeserver/file/ReadSession.hpp" + +namespace castor::tape::tapeFile { + +/** + * Class keeping track of a whole tape read session over an Enstore formatted + * tape. The session will keep track of the overall coherency of the session + * and check for everything to be coherent. The tape should be mounted in + * the drive before the EnstoreReadSession is started (i.e. constructed). + * Likewise, tape unmount is the business of the user. + */ +class EnstoreLargeReadSession : public ReadSession { +public: + /** + * Constructor of the EnstoreReadSession. It will rewind the tape, and check the + * VID value. Throws an exception in case of mismatch. + * @param drive: drive object to which we bind the session + * @param volInfo: volume name of the tape we would like to read from + * @param useLbp: castor.conf option to use or not to use LBP in tapeserverd + */ + EnstoreLargeReadSession(tapeserver::drive::DriveInterface& drive, + const tapeserver::daemon::VolumeInfo& volInfo, + const bool useLbp); + + ~EnstoreLargeReadSession() override = default; +}; + +} // namespace castor::tape::tapeFile diff --git a/tapeserver/castor/tape/tapeserver/file/EnstoreReadSession.cpp b/tapeserver/castor/tape/tapeserver/file/EnstoreReadSession.cpp index 2dbb8fd3c1d293624c0e12c30991df5eb2943f24..1a0a37c38ddc3176cad4f6c89e0571df4e67f77c 100644 --- a/tapeserver/castor/tape/tapeserver/file/EnstoreReadSession.cpp +++ b/tapeserver/castor/tape/tapeserver/file/EnstoreReadSession.cpp @@ -34,11 +34,16 @@ EnstoreReadSession::EnstoreReadSession(tapeserver::drive::DriveInterface &drive, VOL1 vol1; m_drive.readExactBlock(reinterpret_cast<void *>(&vol1), sizeof(vol1), "[ReadSession::ReadSession()] - Reading VOL1"); + // Tapes should have label character 0, but if they were recycled from EnstoreLarge tapes, it could be 3 try { vol1.verify("0"); - } catch (std::exception &e) { - throw TapeFormatError(e.what()); - } + } catch (std::exception& e) { + try { + vol1.verify("3"); + } catch (std::exception& e) { + throw TapeFormatError(e.what()); + }; + }; HeaderChecker::checkVOL1(vol1, volInfo.vid); // after which we are at the end of VOL1 header (e.g. beginning of first file) diff --git a/tapeserver/castor/tape/tapeserver/file/FileReaderFactory.cpp b/tapeserver/castor/tape/tapeserver/file/FileReaderFactory.cpp index 08bd5dc539f1691f601bd17468863d5119292ff9..6104ab784649c39d009a41a3eec4149a8b1b6d25 100644 --- a/tapeserver/castor/tape/tapeserver/file/FileReaderFactory.cpp +++ b/tapeserver/castor/tape/tapeserver/file/FileReaderFactory.cpp @@ -20,6 +20,7 @@ #include "castor/tape/tapeserver/file/CtaFileReader.hpp" #include "castor/tape/tapeserver/file/EnstoreFileReader.hpp" +#include "castor/tape/tapeserver/file/EnstoreLargeFileReader.hpp" #include "castor/tape/tapeserver/file/FileReaderFactory.hpp" #include "castor/tape/tapeserver/file/OsmFileReader.hpp" #include "castor/tape/tapeserver/file/ReadSession.hpp" @@ -44,6 +45,10 @@ std::unique_ptr<FileReader> FileReaderFactory::create(ReadSession& readSession, reader = std::make_unique<EnstoreFileReader>(readSession, fileToRecall); break; } + case LabelFormat::EnstoreLarge: { + reader = std::make_unique<EnstoreLargeFileReader>(readSession, fileToRecall); + break; + } default: { std::ostringstream ossLabelFormat; ossLabelFormat << std::showbase << std::internal << std::setfill('0') << std::hex << std::setw(4) diff --git a/tapeserver/castor/tape/tapeserver/file/ReadSessionFactory.cpp b/tapeserver/castor/tape/tapeserver/file/ReadSessionFactory.cpp index 971582af4fbe76ef496f50077a4fa18066a86c78..d84b2cce8bea7e4e96bb2b49c6ccb07092715e93 100644 --- a/tapeserver/castor/tape/tapeserver/file/ReadSessionFactory.cpp +++ b/tapeserver/castor/tape/tapeserver/file/ReadSessionFactory.cpp @@ -20,6 +20,7 @@ #include "castor/tape/tapeserver/file/CtaReadSession.hpp" #include "castor/tape/tapeserver/file/EnstoreReadSession.hpp" +#include "castor/tape/tapeserver/file/EnstoreLargeReadSession.hpp" #include "castor/tape/tapeserver/file/OsmReadSession.hpp" #include "castor/tape/tapeserver/file/ReadSessionFactory.hpp" #include "common/dataStructures/LabelFormat.hpp" @@ -37,6 +38,8 @@ std::unique_ptr<ReadSession> ReadSessionFactory::create(tapeserver::drive::Drive return std::make_unique<OsmReadSession>(drive, volInfo, useLbp); case LabelFormat::Enstore: return std::make_unique<EnstoreReadSession>(drive, volInfo, useLbp); + case LabelFormat::EnstoreLarge: + return std::make_unique<EnstoreLargeReadSession>(drive, volInfo, useLbp); default: { std::ostringstream ossLabelFormat; ossLabelFormat << std::showbase << std::internal << std::setfill('0') << std::hex << std::setw(4) diff --git a/tapeserver/castor/tape/tapeserver/file/Structures.cpp b/tapeserver/castor/tape/tapeserver/file/Structures.cpp index a5cb83d490d3a535230d129c8af21255f7da611f..62021831b31b2ababe6465d2c7303f34402e2751 100644 --- a/tapeserver/castor/tape/tapeserver/file/Structures.cpp +++ b/tapeserver/castor/tape/tapeserver/file/Structures.cpp @@ -82,7 +82,7 @@ void tapeFile::HDR1EOF1::fillCommon(std::string fileId, std::string VSN, int fSe setString(m_sysCode, std::string("CTA ") + CTA_VERSION); } -void tapeFile::HDR1EOF1::verifyCommon() +void tapeFile::HDR1EOF1::verifyCommon(const bool skipFSecCheck) const { if (!cmpString(m_fileId, "")) @@ -92,10 +92,12 @@ void tapeFile::HDR1EOF1::verifyCommon() if (!cmpString(m_VSN, "")) throw cta::exception::Exception(std::string("Failed verify for the VSN: ") + tapeFile::toString(m_VSN)); - if (cmpString(m_fSec, "0001")) - throw cta::exception::Exception( - std::string("Failed verify for the fSec: ") + - tapeFile::toString(m_fSec)); + if (!skipFSecCheck) { + if (cmpString(m_fSec, "0001")) + throw cta::exception::Exception( + std::string("Failed verify for the fSec: ") + + tapeFile::toString(m_fSec)); + }; if (!cmpString(m_fSeq, "")) throw cta::exception::Exception( std::string("Failed verify for the fSeq: ") + @@ -137,7 +139,7 @@ void tapeFile::HDR1::fill( fillCommon(fileId, VSN, fSeq); } -void tapeFile::HDR1::verify() const { +void tapeFile::HDR1::verify(const bool skipFSecCheck) const { if (cmpString(m_label, "HDR1")) throw cta::exception::Exception(std::string("Failed verify for the HDR1: ") + tapeFile::toString(m_label)); @@ -145,7 +147,7 @@ void tapeFile::HDR1::verify() const { throw cta::exception::Exception(std::string("Failed verify for the blockCount: ") + tapeFile::toString(m_blockCount)); - verifyCommon(); + verifyCommon(skipFSecCheck); } void tapeFile::HDR1PRELABEL::fill(std::string VSN) { @@ -182,7 +184,7 @@ void tapeFile::EOF1::fill( fillCommon(fileId, VSN, fSeq); } -void tapeFile::EOF1::verify() const { +void tapeFile::EOF1::verify(const bool skipFSecCheck) const { if (cmpString(m_label, "EOF1")) throw cta::exception::Exception(std::string("Failed verify for the EOF1: ") + tapeFile::toString(m_label)); @@ -191,7 +193,7 @@ void tapeFile::EOF1::verify() const { std::string("Failed verify for the blockCount: ") + tapeFile::toString(m_blockCount)); - verifyCommon(); + verifyCommon(skipFSecCheck); } void tapeFile::HDR2EOF2::fillCommon(int blockLength, bool driveHasCompression) { @@ -207,12 +209,13 @@ void tapeFile::HDR2EOF2::fillCommon(int blockLength, bool driveHasCompression) { setString(m_aulId, "00"); } -void tapeFile::HDR2EOF2::verifyCommon() +void tapeFile::HDR2EOF2::verifyCommon(const char *const formatCharacter) const { - if (cmpString(m_recordFormat, "F")) + if (cmpString(m_recordFormat, formatCharacter)) { throw cta::exception::Exception( std::string("Failed verify for the recordFormat: ") + tapeFile::toString(m_recordFormat)); + }; if (!cmpString(m_blockLength, "")) throw cta::exception::Exception( std::string("Failed verify for the blockLength: ") + @@ -238,12 +241,12 @@ void tapeFile::HDR2::fill(int blockLength, bool driveHasCompression) { fillCommon(blockLength, driveHasCompression); } -void tapeFile::HDR2::verify() const { +void tapeFile::HDR2::verify(const char *const formatCharacter) const { if (cmpString(m_label, "HDR2")) throw cta::exception::Exception(std::string("Failed verify for the HDR2: ") + tapeFile::toString(m_label)); - verifyCommon(); + verifyCommon(formatCharacter); } void tapeFile::EOF2::fill(int blockLength, bool driveHasCompression) { @@ -252,12 +255,12 @@ void tapeFile::EOF2::fill(int blockLength, bool driveHasCompression) { fillCommon(blockLength, driveHasCompression); } -void tapeFile::EOF2::verify() const { +void tapeFile::EOF2::verify(const char *const formatCharacter) const { if (cmpString(m_label, "EOF2")) throw cta::exception::Exception(std::string("Failed verify for the EOF2: ") + tapeFile::toString(m_label)); - verifyCommon(); + verifyCommon(formatCharacter); } void tapeFile::UHL1UTL1::fillCommon(int fSeq, diff --git a/tapeserver/castor/tape/tapeserver/file/Structures.hpp b/tapeserver/castor/tape/tapeserver/file/Structures.hpp index 22b8220fd334d81dc9c41306b33a413fc02e7196..6f18271b57d13361ce9a31a11521b7274d5286a2 100644 --- a/tapeserver/castor/tape/tapeserver/file/Structures.hpp +++ b/tapeserver/castor/tape/tapeserver/file/Structures.hpp @@ -165,7 +165,7 @@ namespace castor::tape::tapeFile { * Throws an exception if the common field of the structures does * not match expectations. */ - void verifyCommon() const ; + void verifyCommon(const bool skipFSecCheck = false) const ; public: /** @@ -212,7 +212,7 @@ namespace castor::tape::tapeFile { /** * Throws an exception if the structure does not match expectations. */ - void verify() const ; + void verify(const bool skipFSecCheck = false) const ; }; class EOF1 : public HDR1EOF1 { @@ -233,7 +233,7 @@ namespace castor::tape::tapeFile { /** * Throws an exception if the structure does not match expectations. */ - void verify() const ; + void verify(const bool skipFSecCheck = false) const ; }; class HDR1PRELABEL : public HDR1EOF1 { @@ -286,7 +286,7 @@ namespace castor::tape::tapeFile { /** * Throws an exception if the structure does not match expectations. */ - void verifyCommon() const ; + void verifyCommon(const char *const formatCharacter = "F") const ; public: /** * @return The block length @@ -312,7 +312,7 @@ namespace castor::tape::tapeFile { /** * Throws an exception if the structure does not match expectations. */ - void verify() const ; + void verify(const char *const formatCharacter = "F") const ; }; class EOF2 : public HDR2EOF2 { @@ -331,7 +331,7 @@ namespace castor::tape::tapeFile { /** * Throws an exception if the structure does not match expectations. */ - void verify() const ; + void verify(const char *const formatCharacter = "F") const ; }; // The common part of the UHL1 and UTL1 labels