"Fossies" - the Fresh Open Source Software Archive

Member "muscle/zlib/TarFileWriter.cpp" (21 Nov 2020, 7424 Bytes) of package /linux/privat/muscle7.62.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "TarFileWriter.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 7.61_vs_7.62.

    1 /* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */
    2 
    3 #include "dataio/FileDataIO.h"
    4 #include "util/MiscUtilityFunctions.h"
    5 #include "zlib/TarFileWriter.h"
    6 
    7 namespace muscle {
    8 
    9 TarFileWriter :: TarFileWriter()
   10 {
   11    Close();  // this will update our int64 member-variables to their appropriate defaults
   12 }
   13 
   14 TarFileWriter :: TarFileWriter(const char * outputFileName, bool append)
   15 {
   16    (void) SetFile(outputFileName, append);  // SetFile() will call Close(), Close() will initialize our int64 member-variables to their appropriate defaults
   17 }
   18 
   19 TarFileWriter :: TarFileWriter(const DataIORef & dio)
   20 {
   21    (void) SetFile(dio);  // SetFile() will call Close(), Close() will initialize our int64 member-variables to their appropriate defaults
   22 }
   23 
   24 TarFileWriter :: ~TarFileWriter()
   25 {
   26    (void) Close();
   27 }
   28 
   29 status_t TarFileWriter :: Close()
   30 {
   31    const status_t ret = _writerIO() ? FinishCurrentFileDataBlock() : B_NO_ERROR;
   32 
   33    _writerIO.Reset();
   34    _seekableWriterIO.Reset();
   35 
   36    _currentHeaderOffset = -1;
   37    _prestatedFileSize   = 0;
   38    _currentSeekPosition = 0;
   39    return ret;
   40 }
   41 
   42 void TarFileWriter :: SetFile(const DataIORef & dio)
   43 {
   44    (void) Close();
   45 
   46    _writerIO = dio;
   47    (void) _seekableWriterIO.SetFromRefCountableRef(dio);  // _seekableWriterIO be a NULL Ref, and that's okay
   48 }
   49 
   50 status_t TarFileWriter :: SetFile(const char * outputFileName, bool append)
   51 {
   52    (void) Close();
   53 
   54    if (outputFileName)
   55    {
   56       if (append == false) (void) DeleteFile(outputFileName);
   57 
   58       FILE * fpOut = muscleFopen(outputFileName, append?"ab":"wb");
   59       if (fpOut) 
   60       {
   61          FileDataIORef ioRef(newnothrow FileDataIO(fpOut));
   62          if (ioRef()) 
   63          {
   64             SetFile(ioRef);
   65             if (append) _currentSeekPosition = ioRef()->GetLength();
   66             return B_NO_ERROR;
   67          }
   68          else {fclose(fpOut); WARN_OUT_OF_MEMORY;}
   69       }
   70       return B_ERRNO;
   71    }
   72    else return B_NO_ERROR;
   73 }
   74 
   75 static void WriteOctalASCII(uint8 * b, uint64 val, uint8 fieldSize)
   76 {
   77    // gotta pad out the file data to the nearest block boundary!
   78    char formatStr[16]; muscleStrcpy(formatStr, UINT64_FORMAT_SPEC " ");
   79 
   80    char * pi = strchr(formatStr, 'u');
   81    if (pi) *pi = 'o';  // gotta use octal here!
   82 
   83    char tmp[256];
   84    muscleSprintf(tmp, formatStr, val);
   85    const int numChars = muscleMin((int)fieldSize, ((int)(strlen(tmp)+1)));  // include the NUL byte if possible
   86    uint8 * dStart = (b+fieldSize)-numChars;
   87    memcpy(dStart, tmp, numChars);
   88 
   89    // The if-test below shouldn't be necessary, but it's here to
   90    // avoid a spurious warning from gcc under Windows (per Mika)
   91    if (dStart > b) memset(b, '0', dStart-b);  // initial zeros
   92 }
   93 
   94 void TarFileWriter::UpdateCurrentHeaderChecksum()
   95 {
   96    memset(&_currentHeaderBytes[148], ' ', 8);  // when calculating the checksum, the checksum field must be full of spaces
   97 
   98    uint32 checksum = 0;
   99    for (uint32 i=0; i<TAR_BLOCK_SIZE; i++) checksum += _currentHeaderBytes[i];
  100    WriteOctalASCII(&_currentHeaderBytes[148], checksum, 8);
  101 }
  102 
  103 status_t TarFileWriter :: FinishCurrentFileDataBlock()
  104 {
  105    if (_writerIO() == NULL) return B_BAD_OBJECT;
  106 
  107    status_t ret;
  108    if (_currentHeaderOffset >= 0)
  109    {
  110       const uint64 currentFileLength = _currentSeekPosition-(_currentHeaderOffset+TAR_BLOCK_SIZE);
  111       const int64 extraBytes = (_currentSeekPosition%TAR_BLOCK_SIZE);
  112       if (extraBytes != 0)
  113       {
  114          const int64 numPadBytes = (TAR_BLOCK_SIZE-extraBytes);
  115          uint8 zeros[TAR_BLOCK_SIZE]; memset(zeros, 0, (size_t) numPadBytes);
  116 
  117          const uint32 numBytesWritten = _writerIO()->WriteFully(zeros, (uint32) numPadBytes);
  118          _currentSeekPosition += numBytesWritten;
  119          if (numBytesWritten != (uint32) numPadBytes) return B_IO_ERROR;
  120       }
  121 
  122       if (_seekableWriterIO())
  123       {
  124          WriteOctalASCII(&_currentHeaderBytes[124], currentFileLength, 12);
  125          UpdateCurrentHeaderChecksum();
  126 
  127          if (_seekableWriterIO()->Seek(_currentHeaderOffset, SeekableDataIO::IO_SEEK_SET).IsError(ret)) return ret;
  128          _currentSeekPosition = _currentHeaderOffset;
  129  
  130          const uint32 numBytesWritten = _seekableWriterIO()->WriteFully(_currentHeaderBytes, sizeof(_currentHeaderBytes));
  131          _currentSeekPosition += _currentHeaderOffset;
  132          if (numBytesWritten != sizeof(_currentHeaderBytes)) return B_IO_ERROR;
  133 
  134          if (_seekableWriterIO()->Seek(0, SeekableDataIO::IO_SEEK_END).IsOK(ret)) _currentSeekPosition = _seekableWriterIO()->GetLength();
  135                                                                              else return ret;
  136       }
  137       else if (_prestatedFileSize != currentFileLength)
  138       {
  139          LogTime(MUSCLE_LOG_ERROR, "TarFileWriter::FinishCurrentFileDataBlock():  DataIO isn't seekable, and the current entry's  file-length (" UINT64_FORMAT_SPEC ") doesn't match the prestated file-length (" UINT64_FORMAT_SPEC ")!  Can't update the tar entry header!\n", currentFileLength, _prestatedFileSize);
  140          return B_BAD_ARGUMENT;
  141       }
  142 
  143       _currentHeaderOffset = -1;
  144       _prestatedFileSize   = 0;
  145    }
  146    return B_NO_ERROR;
  147 }
  148 
  149 status_t TarFileWriter :: WriteFileHeader(const char * fileName, uint32 fileMode, uint32 ownerID, uint32 groupID, uint64 modificationTime, int linkIndicator, const char * linkedFileName, uint64 prestatedFileSize)
  150 {
  151    if ((strlen(fileName) > 100)||((linkedFileName)&&(strlen(linkedFileName)>100))) return B_BAD_ARGUMENT;  // string fields are only 100 chars long!
  152 
  153    status_t ret;
  154    if (FinishCurrentFileDataBlock().IsError(ret)) return ret;  // should pad out position out to a multiple of 512, if necessary
  155 
  156    if ((_currentSeekPosition%TAR_BLOCK_SIZE) != 0) return B_BAD_OBJECT;
  157 
  158    _currentHeaderOffset = _currentSeekPosition;
  159    memset(_currentHeaderBytes, 0, sizeof(_currentHeaderBytes));
  160    muscleStrncpy((char *)(&_currentHeaderBytes[0]), fileName, sizeof(_currentHeaderBytes));
  161 
  162    WriteOctalASCII(&_currentHeaderBytes[100], fileMode, 8);
  163    WriteOctalASCII(&_currentHeaderBytes[108], ownerID, 8);
  164    WriteOctalASCII(&_currentHeaderBytes[116], groupID, 8);
  165    WriteOctalASCII(&_currentHeaderBytes[124], prestatedFileSize, 12);
  166 
  167    const uint64 secondsSince1970 = MicrosToSeconds(modificationTime);
  168    if (secondsSince1970 != 0) WriteOctalASCII(&_currentHeaderBytes[136], secondsSince1970, 12);
  169 
  170    _currentHeaderBytes[156] = (uint8) (linkIndicator+'0');
  171    if (linkedFileName) muscleStrncpy((char *)(&_currentHeaderBytes[157]), linkedFileName, sizeof(_currentHeaderBytes)-157);
  172 
  173    UpdateCurrentHeaderChecksum();
  174 
  175    // We write out the header as it is now, in order to keep the file offsets correct... but we'll rewrite it again later
  176    // when we know the actual file size.
  177    const uint32 numBytesWritten = _writerIO()->WriteFully(_currentHeaderBytes, sizeof(_currentHeaderBytes));
  178    _currentSeekPosition += numBytesWritten;
  179    if (numBytesWritten == sizeof(_currentHeaderBytes))
  180    {
  181       _prestatedFileSize = prestatedFileSize;
  182       return B_NO_ERROR;
  183    }
  184    else return B_IO_ERROR;
  185 }
  186 
  187 status_t TarFileWriter :: WriteFileData(const uint8 * fileData, uint32 numBytes)
  188 {
  189    if ((_writerIO() == NULL)||(_currentHeaderOffset < 0)) return B_BAD_OBJECT;
  190 
  191    const uint32 numBytesWritten = _writerIO()->WriteFully(fileData, numBytes);
  192    _currentSeekPosition += numBytesWritten;
  193    return (numBytesWritten == numBytes) ? B_NO_ERROR : B_IO_ERROR;
  194 }
  195 
  196 } // end namespace muscle