Пример #1
0
bool wxTarOutputStream::CloseEntry()
{
    if (!IsOpened())
        return true;

    if (m_pos < m_maxpos) {
        wxASSERT(m_parent_o_stream->IsSeekable());
        m_parent_o_stream->SeekO(m_datapos + m_maxpos);
        m_lasterror = m_parent_o_stream->GetLastError();
        m_pos = m_maxpos;
    }

    if (IsOk()) {
        wxFileOffset size = RoundUpSize(m_pos);
        if (size > m_pos) {
            m_hdr->Clear(size - m_pos);
            m_parent_o_stream->Write(m_hdr, size - m_pos);
            m_lasterror = m_parent_o_stream->GetLastError();
        }
        m_tarsize += size;
    }

    if (IsOk() && m_pos != m_size)
        ModifyHeader();

    m_pos = wxInvalidOffset;
    m_maxpos = wxInvalidOffset;
    m_size = wxInvalidOffset;
    m_headpos = wxInvalidOffset;
    m_datapos = wxInvalidOffset;

    return IsOk();
}
Пример #2
0
bool wxTarInputStream::CloseEntry()
{
    if (m_lasterror == wxSTREAM_READ_ERROR)
        return false;
    if (!IsOpened())
        return true;

    wxFileOffset size = RoundUpSize(m_size);
    wxFileOffset remainder = size - m_pos;

    if (remainder && m_parent_i_stream->IsSeekable()) {
        wxLogNull nolog;
        if (m_parent_i_stream->SeekI(remainder, wxFromCurrent)
                != wxInvalidOffset)
            remainder = 0;
    }

    if (remainder) {
        const int BUFSIZE = 8192;
        wxCharBuffer buf(BUFSIZE);

        while (remainder > 0 && m_parent_i_stream->IsOk())
            remainder -= m_parent_i_stream->Read(
                    buf.data(), wxMin(BUFSIZE, remainder)).LastRead();
    }

    m_pos = wxInvalidOffset;
    m_offset += size;
    m_lasterror = m_parent_i_stream->GetLastError();

    return IsOk();
}
Пример #3
0
void wxTarOutputStream::SetExtendedHeader(const wxString& key,
                                          const wxString& value)
{
    if (m_pax) {
#if wxUSE_UNICODE
        const wxCharBuffer utf_key = key.utf8_str();
        const wxCharBuffer utf_value = value.utf8_str();
#else
        const wxWX2WCbuf wide_key = key.wc_str(GetConv());
        const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key);

        const wxWX2WCbuf wide_value = value.wc_str(GetConv());
        const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value);
#endif // wxUSE_UNICODE/!wxUSE_UNICODE

        // a small buffer to format the length field in
        char buf[32];
        // length of "99<space><key>=<value>\n"
        unsigned long length = strlen(utf_value) + strlen(utf_key) + 5;
        sprintf(buf, "%lu", length);
        // the length includes itself
        size_t lenlen = strlen(buf);
        if (lenlen != 2) {
            length += lenlen - 2;
            sprintf(buf, "%lu", length);
            if (strlen(buf) > lenlen)
                sprintf(buf, "%lu", ++length);
        }

        // reallocate m_extendedHdr if it's not big enough
        if (m_extendedSize < length) {
            size_t rounded = RoundUpSize(length);
            m_extendedSize <<= 1;
            if (rounded > m_extendedSize)
                m_extendedSize = rounded;
            char *oldHdr = m_extendedHdr;
            m_extendedHdr = new char[m_extendedSize];
            if (oldHdr) {
                strcpy(m_extendedHdr, oldHdr);
                delete oldHdr;
            } else {
                *m_extendedHdr = 0;
            }
        }

        // append the new record
        char *append = strchr(m_extendedHdr, 0);
        sprintf(append, "%s %s=%s\012", buf,
                (const char*)utf_key, (const char*)utf_value);
    }
    else {
        // if not pax then make a list of fields to report as errors
        if (!m_badfit.empty())
            m_badfit += wxT(", ");
        m_badfit += key;
    }
}
Пример #4
0
void KRBundle::append(KRResource &resource)
{
    // Serialize resource to binary representation
    KRDataBlock resource_data;
    resource.save(resource_data);
    
    std::string file_name = resource.getName() + "." + resource.getExtension();
    
    // Padding is added at the end of file to align next header to a 512 byte boundary.  Padding at the end of the archive includes an additional 1024 bytes -- two zero-ed out file headers that mark the end of the archive
    size_t padding_size = RoundUpSize(resource_data.getSize()) - resource_data.getSize() + KRENGINE_KRBUNDLE_HEADER_SIZE * 2;
    
    m_pData->expand(KRENGINE_KRBUNDLE_HEADER_SIZE + resource_data.getSize() + padding_size - KRENGINE_KRBUNDLE_HEADER_SIZE * 2); // We will overwrite the existing zero-ed out file headers that marked the end of the archive, so we don't have to include their size here
    
    m_pData->lock();
    
    // Get location of file header
    tar_header_type *file_header = (tar_header_type *)((unsigned char *)m_pData->getEnd() - padding_size - resource_data.getSize() - KRENGINE_KRBUNDLE_HEADER_SIZE);
    
    // Zero out new file header
    memset(file_header, 0, KRENGINE_KRBUNDLE_HEADER_SIZE);
    
    // Copy resource data
    resource_data.lock();
    memcpy((unsigned char *)m_pData->getEnd() - padding_size - resource_data.getSize(), resource_data.getStart(), resource_data.getSize());
    resource_data.unlock();
    
    // Zero out alignment padding and terminating set of file header blocks
    memset((unsigned char *)m_pData->getEnd() - padding_size, 0, padding_size);
    
    // Populate new file header fields
    strncpy(file_header->file_name, file_name.c_str(), 100);
    strcpy(file_header->file_mode, "000644 ");
    strcpy(file_header->owner_id, "000000 ");
    strcpy(file_header->group_id, "000000 ");
    sprintf(file_header->file_size, "%011o", (int)resource_data.getSize());
    file_header->file_size[11] = ' '; // Terminate with space rather than '\0'
    sprintf(file_header->mod_time, "%011o", (int)time(NULL));
    file_header->mod_time[11] = ' '; // Terminate with space rather than '\0'
    
    // Calculate and write checksum for header
    memset(file_header->checksum, ' ', 8); // Must be filled with spaces and no null terminator during checksum calculation
    int check_sum = 0;
    for(int i=0; i < KRENGINE_KRBUNDLE_HEADER_SIZE; i++) {
        unsigned char *byte_ptr = (unsigned char *)file_header;
        check_sum += byte_ptr[i];
    }
    sprintf(file_header->checksum, "%07o", check_sum);
    
    m_pData->unlock();
}
Пример #5
0
bool wxTarOutputStream::Close()
{
    if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten))
        return false;

    m_hdr->Clear();
    int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor)
                    - m_tarsize) / TAR_BLOCKSIZE;
    while (count--)
        m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE);

    m_tarsize = 0;
    m_tarstart = wxInvalidOffset;
    m_lasterror = m_parent_o_stream->GetLastError();
    m_endrecWritten = true;
    return IsOk();
}
Пример #6
0
KRBundle::KRBundle(KRContext &context, std::string name, KRDataBlock *pData) : KRResource(context, name)
{
    m_pData = pData;
    
    __int64_t file_pos = 0;
    while(file_pos < m_pData->getSize()) {
        tar_header_type file_header;
        m_pData->copy(&file_header, file_pos, sizeof(file_header));
        size_t file_size = strtol(file_header.file_size, NULL, 8);
        file_pos += 512; // Skip past the header to the file contents
        if(file_header.file_name[0] != '\0' && file_header.file_name[0] != '.') {
            // We ignore the last two records in the tar file, which are zero'ed out tar_header structures
            KRDataBlock *pFileData = pData->getSubBlock(file_pos, file_size);
            context.loadResource(file_header.file_name, pFileData);
        }
        file_pos += RoundUpSize(file_size);
    }
}
Пример #7
0
bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs)
{
    if (!recs)
        recs = new wxTarHeaderRecords;

    // round length up to a whole number of blocks
    size_t len = m_hdr->GetOctal(TAR_SIZE);
    size_t size = RoundUpSize(len);

    // read in the whole header since it should be small
    wxCharBuffer buf(size);
    size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead();
    if (lastread < len)
        len = lastread;
    buf.data()[len] = 0;
    m_offset += lastread;

    size_t recPos, recSize;
    bool ok = true;

    for (recPos = 0; recPos < len && ok; recPos += recSize) {
        char *pRec = buf.data() + recPos;
        char *p = pRec;

        // read the record size (byte count in ascii decimal)
        recSize = 0;
        while (isdigit((unsigned char) *p))
            recSize = recSize * 10 + *p++ - '0';

        // validity checks
        if (recPos + recSize > len)
            break;
        if (recSize < p - pRec + (size_t)3 || *p != ' '
                || pRec[recSize - 1] != '\012') {
            ok = false;
            continue;
        }

        // replace the final '\n' with a nul, to terminate value
        pRec[recSize - 1] = 0;
        // the key is here, following the space
        char *pKey = ++p;

        // look forward for the '=', the value follows
        while (*p && *p != '=')
            p++;
        if (!*p) {
            ok = false;
            continue;
        }
        // replace the '=' with a nul, to terminate the key
        *p++ = 0;

        wxString key(wxConvUTF8.cMB2WC(pKey), GetConv());
        wxString value(wxConvUTF8.cMB2WC(p), GetConv());

        // an empty value unsets a previously given value
        if (value.empty())
            recs->erase(key);
        else
            (*recs)[key] = value;
    }

    if (!ok || recPos < len || size != lastread) {
        wxLogWarning(_("invalid data in extended tar header"));
        return false;
    }

    return true;
}
Пример #8
0
bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
{
    m_hdr->Clear();

    SetHeaderPath(entry.GetName(wxPATH_UNIX));

    SetHeaderNumber(TAR_MODE, entry.GetMode());
    SetHeaderNumber(TAR_UID, entry.GetUserId());
    SetHeaderNumber(TAR_GID, entry.GetGroupId());

    if (entry.GetSize() == wxInvalidOffset)
        entry.SetSize(0);
    m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize());

    SetHeaderDate(wxT("mtime"), entry.GetDateTime());
    if (entry.GetAccessTime().IsValid())
        SetHeaderDate(wxT("atime"), entry.GetAccessTime());
    if (entry.GetCreateTime().IsValid())
        SetHeaderDate(wxT("ctime"), entry.GetCreateTime());

    *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag());

    strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC);
    strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION);

    SetHeaderString(TAR_LINKNAME, entry.GetLinkName());
    SetHeaderString(TAR_UNAME, entry.GetUserName());
    SetHeaderString(TAR_GNAME, entry.GetGroupName());

    if (~entry.GetDevMajor())
        SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor());
    if (~entry.GetDevMinor())
        SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor());

    m_chksum = m_hdr->Sum();
    m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
    if (!m_large)
        m_chksum -= m_hdr->SumField(TAR_SIZE);

    // The main header is now fully prepared so we know what extended headers
    // (if any) will be needed. Output any extended headers before writing
    // the main header.
    if (m_extendedHdr && *m_extendedHdr) {
        wxASSERT(m_pax);
        // the extended headers are written to the tar as a file entry,
        // so prepare a regular header block for the pseudo-file.
        if (!m_hdr2)
            m_hdr2 = new wxTarHeaderBlock;
        m_hdr2->Clear();

        // an old tar that doesn't understand extended headers will
        // extract it as a file, so give these fields reasonable values
        // so that the user will have access to read and remove it.
        m_hdr2->SetPath(PaxHeaderPath(wxT("%d/PaxHeaders.%p/%f"),
                                      entry.GetName(wxPATH_UNIX)), GetConv());
        m_hdr2->SetOctal(TAR_MODE, 0600);
        strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID));
        strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID));
        size_t length = strlen(m_extendedHdr);
        m_hdr2->SetOctal(TAR_SIZE, length);
        strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME));
        *m_hdr2->Get(TAR_TYPEFLAG) = 'x';
        strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC);
        strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION);
        strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME));
        strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME));

        m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum());

        m_hdr2->Write(*m_parent_o_stream);
        m_tarsize += TAR_BLOCKSIZE;

        size_t rounded = RoundUpSize(length);
        memset(m_extendedHdr + length, 0, rounded - length);
        m_parent_o_stream->Write(m_extendedHdr, rounded);
        m_tarsize += rounded;

        *m_extendedHdr = 0;

        // update m_headpos which is used to seek back to fix up the file
        // length if it is not known in advance
        if (m_tarstart != wxInvalidOffset)
            m_headpos = m_tarstart + m_tarsize;
    }

    // if don't have extended headers just report error
    if (!m_badfit.empty()) {
        wxASSERT(!m_pax);
        wxLogWarning(_("%s did not fit the tar header for entry '%s'"),
                     m_badfit.c_str(), entry.GetName().c_str());
        m_badfit.clear();
    }

    m_hdr->Write(*m_parent_o_stream);
    m_tarsize += TAR_BLOCKSIZE;
    m_lasterror = m_parent_o_stream->GetLastError();

    return IsOk();
}