TarFileWriter.cpp (muscle7.61) | : | TarFileWriter.cpp (muscle7.62) | ||
---|---|---|---|---|
/* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc. See the inclu ded LICENSE.txt file for details. */ | /* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc. See the inclu ded LICENSE.txt file for details. */ | |||
#include "dataio/FileDataIO.h" | #include "dataio/FileDataIO.h" | |||
#include "util/MiscUtilityFunctions.h" | #include "util/MiscUtilityFunctions.h" | |||
#include "zlib/TarFileWriter.h" | #include "zlib/TarFileWriter.h" | |||
namespace muscle { | namespace muscle { | |||
TarFileWriter :: TarFileWriter() | TarFileWriter :: TarFileWriter() | |||
: _currentHeaderOffset(-1) | ||||
{ | { | |||
// empty | Close(); // this will update our int64 member-variables to their appropriate defaults | |||
} | } | |||
TarFileWriter :: TarFileWriter(const char * outputFileName, bool append) | TarFileWriter :: TarFileWriter(const char * outputFileName, bool append) | |||
: _currentHeaderOffset(-1) | ||||
{ | { | |||
(void) SetFile(outputFileName, append); | (void) SetFile(outputFileName, append); // SetFile() will call Close(), Clos e() will initialize our int64 member-variables to their appropriate defaults | |||
} | } | |||
TarFileWriter :: TarFileWriter(const SeekableDataIORef & dio) | TarFileWriter :: TarFileWriter(const DataIORef & dio) | |||
: _writerIO(dio) | ||||
, _currentHeaderOffset(-1) | ||||
{ | { | |||
// empty | (void) SetFile(dio); // SetFile() will call Close(), Close() will initialize our int64 member-variables to their appropriate defaults | |||
} | } | |||
TarFileWriter :: ~TarFileWriter() | TarFileWriter :: ~TarFileWriter() | |||
{ | { | |||
(void) Close(); | (void) Close(); | |||
} | } | |||
status_t TarFileWriter :: Close() | status_t TarFileWriter :: Close() | |||
{ | { | |||
const status_t ret = _writerIO() ? FinishCurrentFileDataBlock() : B_NO_ERROR; | const status_t ret = _writerIO() ? FinishCurrentFileDataBlock() : B_NO_ERROR; | |||
_writerIO.Reset(); // do this no matter what | ||||
_writerIO.Reset(); | ||||
_seekableWriterIO.Reset(); | ||||
_currentHeaderOffset = -1; | ||||
_prestatedFileSize = 0; | ||||
_currentSeekPosition = 0; | ||||
return ret; | return ret; | |||
} | } | |||
void TarFileWriter :: SetFile(const SeekableDataIORef & dio) | void TarFileWriter :: SetFile(const DataIORef & dio) | |||
{ | { | |||
(void) Close(); | (void) Close(); | |||
_writerIO = dio; | _writerIO = dio; | |||
(void) _seekableWriterIO.SetFromRefCountableRef(dio); // _seekableWriterIO b e a NULL Ref, and that's okay | ||||
} | } | |||
status_t TarFileWriter :: SetFile(const char * outputFileName, bool append) | status_t TarFileWriter :: SetFile(const char * outputFileName, bool append) | |||
{ | { | |||
(void) Close(); | (void) Close(); | |||
_writerIO.Reset(); | ||||
if (outputFileName) | if (outputFileName) | |||
{ | { | |||
if (append == false) (void) DeleteFile(outputFileName); | if (append == false) (void) DeleteFile(outputFileName); | |||
FILE * fpOut = muscleFopen(outputFileName, append?"ab":"wb"); | FILE * fpOut = muscleFopen(outputFileName, append?"ab":"wb"); | |||
if (fpOut) | if (fpOut) | |||
{ | { | |||
_writerIO.SetRef(newnothrow FileDataIO(fpOut)); | FileDataIORef ioRef(newnothrow FileDataIO(fpOut)); | |||
if (_writerIO()) return B_NO_ERROR; | if (ioRef()) | |||
else {fclose(fpOut); WARN_OUT_OF_MEMORY;} | { | |||
SetFile(ioRef); | ||||
if (append) _currentSeekPosition = ioRef()->GetLength(); | ||||
return B_NO_ERROR; | ||||
} | ||||
else {fclose(fpOut); WARN_OUT_OF_MEMORY;} | ||||
} | } | |||
return B_ERRNO; | return B_ERRNO; | |||
} | } | |||
else return B_NO_ERROR; | else return B_NO_ERROR; | |||
} | } | |||
static void WriteOctalASCII(uint8 * b, uint64 val, uint8 fieldSize) | static void WriteOctalASCII(uint8 * b, uint64 val, uint8 fieldSize) | |||
{ | { | |||
// gotta pad out the file data to the nearest block boundary! | // gotta pad out the file data to the nearest block boundary! | |||
char formatStr[16]; muscleStrcpy(formatStr, UINT64_FORMAT_SPEC " "); | char formatStr[16]; muscleStrcpy(formatStr, UINT64_FORMAT_SPEC " "); | |||
skipping to change at line 86 | skipping to change at line 94 | |||
muscleSprintf(tmp, formatStr, val); | muscleSprintf(tmp, formatStr, val); | |||
const int numChars = muscleMin((int)fieldSize, ((int)(strlen(tmp)+1))); // i nclude the NUL byte if possible | const int numChars = muscleMin((int)fieldSize, ((int)(strlen(tmp)+1))); // i nclude the NUL byte if possible | |||
uint8 * dStart = (b+fieldSize)-numChars; | uint8 * dStart = (b+fieldSize)-numChars; | |||
memcpy(dStart, tmp, numChars); | memcpy(dStart, tmp, numChars); | |||
// The if-test below shouldn't be necessary, but it's here to | // The if-test below shouldn't be necessary, but it's here to | |||
// avoid a spurious warning from gcc under Windows (per Mika) | // avoid a spurious warning from gcc under Windows (per Mika) | |||
if (dStart > b) memset(b, '0', dStart-b); // initial zeros | if (dStart > b) memset(b, '0', dStart-b); // initial zeros | |||
} | } | |||
void TarFileWriter::UpdateCurrentHeaderChecksum() | ||||
{ | ||||
memset(&_currentHeaderBytes[148], ' ', 8); // when calculating the checksum, | ||||
the checksum field must be full of spaces | ||||
uint32 checksum = 0; | ||||
for (uint32 i=0; i<TAR_BLOCK_SIZE; i++) checksum += _currentHeaderBytes[i]; | ||||
WriteOctalASCII(&_currentHeaderBytes[148], checksum, 8); | ||||
} | ||||
status_t TarFileWriter :: FinishCurrentFileDataBlock() | status_t TarFileWriter :: FinishCurrentFileDataBlock() | |||
{ | { | |||
if (_writerIO() == NULL) return B_BAD_OBJECT; | if (_writerIO() == NULL) return B_BAD_OBJECT; | |||
status_t ret; | status_t ret; | |||
if (_currentHeaderOffset >= 0) | if (_currentHeaderOffset >= 0) | |||
{ | { | |||
const int64 currentPos = GetCurrentSeekPosition(); | const uint64 currentFileLength = _currentSeekPosition-(_currentHeaderOffse | |||
const uint64 currentFileLength = currentPos-(_currentHeaderOffset+TAR_BLOC | t+TAR_BLOCK_SIZE); | |||
K_SIZE); | const int64 extraBytes = (_currentSeekPosition%TAR_BLOCK_SIZE); | |||
const int64 extraBytes = (currentPos%TAR_BLOCK_SIZE); | ||||
if (extraBytes != 0) | if (extraBytes != 0) | |||
{ | { | |||
const int64 numPadBytes = (TAR_BLOCK_SIZE-extraBytes); | const int64 numPadBytes = (TAR_BLOCK_SIZE-extraBytes); | |||
uint8 zeros[TAR_BLOCK_SIZE]; memset(zeros, 0, (size_t) numPadBytes); | uint8 zeros[TAR_BLOCK_SIZE]; memset(zeros, 0, (size_t) numPadBytes); | |||
if (_writerIO()->WriteFully(zeros, (uint32) numPadBytes) != (uint32) nu | ||||
mPadBytes) return B_IO_ERROR; | const uint32 numBytesWritten = _writerIO()->WriteFully(zeros, (uint32) | |||
numPadBytes); | ||||
_currentSeekPosition += numBytesWritten; | ||||
if (numBytesWritten != (uint32) numPadBytes) return B_IO_ERROR; | ||||
} | } | |||
WriteOctalASCII(&_currentHeaderBytes[124], currentFileLength, 12); | if (_seekableWriterIO()) | |||
{ | ||||
WriteOctalASCII(&_currentHeaderBytes[124], currentFileLength, 12); | ||||
UpdateCurrentHeaderChecksum(); | ||||
if (_seekableWriterIO()->Seek(_currentHeaderOffset, SeekableDataIO::IO_ | ||||
SEEK_SET).IsError(ret)) return ret; | ||||
_currentSeekPosition = _currentHeaderOffset; | ||||
uint32 checksum = 0; | const uint32 numBytesWritten = _seekableWriterIO()->WriteFully(_current | |||
for (uint32 i=0; i<TAR_BLOCK_SIZE; i++) checksum += _currentHeaderBytes[i] | HeaderBytes, sizeof(_currentHeaderBytes)); | |||
; | _currentSeekPosition += _currentHeaderOffset; | |||
WriteOctalASCII(&_currentHeaderBytes[148], checksum, 8); | if (numBytesWritten != sizeof(_currentHeaderBytes)) return B_IO_ERROR; | |||
if (_writerIO()->Seek(_currentHeaderOffset, SeekableDataIO::IO_SEEK_SET).I | if (_seekableWriterIO()->Seek(0, SeekableDataIO::IO_SEEK_END).IsOK(ret) | |||
sError(ret)) return ret; | ) _currentSeekPosition = _seekableWriterIO()->GetLength(); | |||
if (_writerIO()->WriteFully(_currentHeaderBytes, sizeof(_currentHeaderByte | els | |||
s)) != sizeof(_currentHeaderBytes)) return B_IO_ERROR; | e return ret; | |||
if (_writerIO()->Seek(0, SeekableDataIO::IO_SEEK_END).IsError(ret)) return | } | |||
ret; | else if (_prestatedFileSize != currentFileLength) | |||
{ | ||||
LogTime(MUSCLE_LOG_ERROR, "TarFileWriter::FinishCurrentFileDataBlock(): | ||||
DataIO isn't seekable, and the current entry's file-length (" UINT64_FORMAT_S | ||||
PEC ") doesn't match the prestated file-length (" UINT64_FORMAT_SPEC ")! Can't | ||||
update the tar entry header!\n", currentFileLength, _prestatedFileSize); | ||||
return B_BAD_ARGUMENT; | ||||
} | ||||
_currentHeaderOffset = -1; | _currentHeaderOffset = -1; | |||
_prestatedFileSize = 0; | ||||
} | } | |||
return B_NO_ERROR; | return B_NO_ERROR; | |||
} | } | |||
int64 TarFileWriter :: GetCurrentSeekPosition() const | status_t TarFileWriter :: WriteFileHeader(const char * fileName, uint32 fileMode | |||
{ | , uint32 ownerID, uint32 groupID, uint64 modificationTime, int linkIndicator, co | |||
return _writerIO() ? _writerIO()->GetPosition() : -1; | nst char * linkedFileName, uint64 prestatedFileSize) | |||
} | ||||
status_t TarFileWriter :: WriteFileHeader(const char * fileName, uint32 fileMode | ||||
, uint32 ownerID, uint32 groupID, uint64 modificationTime, int linkIndicator, co | ||||
nst char * linkedFileName) | ||||
{ | { | |||
if ((strlen(fileName) > 100)||((linkedFileName)&&(strlen(linkedFileName)>100) )) return B_BAD_ARGUMENT; // string fields are only 100 chars long! | if ((strlen(fileName) > 100)||((linkedFileName)&&(strlen(linkedFileName)>100) )) return B_BAD_ARGUMENT; // string fields are only 100 chars long! | |||
status_t ret; | status_t ret; | |||
if (FinishCurrentFileDataBlock().IsError(ret)) return ret; // should pad out position out to a multiple of 512, if necessary | if (FinishCurrentFileDataBlock().IsError(ret)) return ret; // should pad out position out to a multiple of 512, if necessary | |||
const int64 curSeekPos = GetCurrentSeekPosition(); | if ((_currentSeekPosition%TAR_BLOCK_SIZE) != 0) return B_BAD_OBJECT; | |||
if ((curSeekPos < 0)||((curSeekPos%TAR_BLOCK_SIZE) != 0)) return B_BAD_OBJECT | ||||
; | ||||
_currentHeaderOffset = curSeekPos; | _currentHeaderOffset = _currentSeekPosition; | |||
memset(_currentHeaderBytes, 0, sizeof(_currentHeaderBytes)); | memset(_currentHeaderBytes, 0, sizeof(_currentHeaderBytes)); | |||
muscleStrncpy((char *)(&_currentHeaderBytes[0]), fileName, sizeof(_currentHea derBytes)); | muscleStrncpy((char *)(&_currentHeaderBytes[0]), fileName, sizeof(_currentHea derBytes)); | |||
WriteOctalASCII(&_currentHeaderBytes[100], fileMode, 8); | WriteOctalASCII(&_currentHeaderBytes[100], fileMode, 8); | |||
WriteOctalASCII(&_currentHeaderBytes[108], ownerID, 8); | WriteOctalASCII(&_currentHeaderBytes[108], ownerID, 8); | |||
WriteOctalASCII(&_currentHeaderBytes[116], groupID, 8); | WriteOctalASCII(&_currentHeaderBytes[116], groupID, 8); | |||
WriteOctalASCII(&_currentHeaderBytes[124], prestatedFileSize, 12); | ||||
const uint64 secondsSince1970 = MicrosToSeconds(modificationTime); | const uint64 secondsSince1970 = MicrosToSeconds(modificationTime); | |||
if (secondsSince1970 != 0) WriteOctalASCII(&_currentHeaderBytes[136], seconds Since1970, 12); | if (secondsSince1970 != 0) WriteOctalASCII(&_currentHeaderBytes[136], seconds Since1970, 12); | |||
memset(&_currentHeaderBytes[148], ' ', 8); // these spaces are used later on , when calculating the header checksum | ||||
_currentHeaderBytes[156] = (uint8) (linkIndicator+'0'); | _currentHeaderBytes[156] = (uint8) (linkIndicator+'0'); | |||
if (linkedFileName) muscleStrncpy((char *)(&_currentHeaderBytes[157]), linked FileName, sizeof(_currentHeaderBytes)-157); | if (linkedFileName) muscleStrncpy((char *)(&_currentHeaderBytes[157]), linked FileName, sizeof(_currentHeaderBytes)-157); | |||
UpdateCurrentHeaderChecksum(); | ||||
// We write out the header as it is now, in order to keep the file offsets co rrect... but we'll rewrite it again later | // We write out the header as it is now, in order to keep the file offsets co rrect... but we'll rewrite it again later | |||
// when we know the actual file size. | // when we know the actual file size. | |||
return (_writerIO()->WriteFully(_currentHeaderBytes, sizeof(_currentHeaderByt | const uint32 numBytesWritten = _writerIO()->WriteFully(_currentHeaderBytes, s | |||
es)) == sizeof(_currentHeaderBytes)) ? B_NO_ERROR : B_IO_ERROR; | izeof(_currentHeaderBytes)); | |||
_currentSeekPosition += numBytesWritten; | ||||
if (numBytesWritten == sizeof(_currentHeaderBytes)) | ||||
{ | ||||
_prestatedFileSize = prestatedFileSize; | ||||
return B_NO_ERROR; | ||||
} | ||||
else return B_IO_ERROR; | ||||
} | } | |||
status_t TarFileWriter :: WriteFileData(const uint8 * fileData, uint32 numBytes) | status_t TarFileWriter :: WriteFileData(const uint8 * fileData, uint32 numBytes) | |||
{ | { | |||
if ((_writerIO() == NULL)||(_currentHeaderOffset < 0)) return B_BAD_OBJECT; | if ((_writerIO() == NULL)||(_currentHeaderOffset < 0)) return B_BAD_OBJECT; | |||
return (_writerIO()->WriteFully(fileData, numBytes) == numBytes) ? B_NO_ERROR | ||||
: B_IO_ERROR; | const uint32 numBytesWritten = _writerIO()->WriteFully(fileData, numBytes); | |||
_currentSeekPosition += numBytesWritten; | ||||
return (numBytesWritten == numBytes) ? B_NO_ERROR : B_IO_ERROR; | ||||
} | } | |||
} // end namespace muscle | } // end namespace muscle | |||
End of changes. 26 change blocks. | ||||
49 lines changed or deleted | 88 lines changed or added |