X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6df6e35a3eae74404f15f8f7c09ce19c29f47b4a..acd32ffcdb319f162633c20e0202db3f8542998a:/src/common/tarstrm.cpp diff --git a/src/common/tarstrm.cpp b/src/common/tarstrm.cpp index 18412660d7..033c34cf09 100644 --- a/src/common/tarstrm.cpp +++ b/src/common/tarstrm.cpp @@ -26,12 +26,14 @@ #include "wx/buffer.h" #include "wx/datetime.h" -#include "wx/ptr_scpd.h" +#include "wx/scopedptr.h" #include "wx/filename.h" +#include "wx/thread.h" #include #ifdef __UNIX__ +#include #include #endif @@ -108,10 +110,10 @@ wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const static const wxChar *empty[] = { NULL }; switch (type) { - case wxSTREAM_PROTOCOL: return protocols; - case wxSTREAM_MIMETYPE: return mimetypes; - case wxSTREAM_FILEEXTENSION: return fileexts; - default: return empty; + case wxSTREAM_PROTOCOL: return protocols; + case wxSTREAM_MIMETYPE: return mimetypes; + case wxSTREAM_FILEEXT: return fileexts; + default: return empty; } } @@ -228,7 +230,7 @@ wxUint32 wxTarHeaderBlock::SumField(int id) } bool wxTarHeaderBlock::Read(wxInputStream& in) -{ +{ bool ok = true; for (int id = 0; id < TAR_NUMFIELDS && ok; id++) @@ -247,7 +249,7 @@ bool wxTarHeaderBlock::Write(wxOutputStream& out) return ok; } -bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id) +inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id) { return out.Write(Get(id), Len(id)).LastWrite() == Len(id); } @@ -266,11 +268,11 @@ wxTarNumber wxTarHeaderBlock::GetOctal(int id) bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n) { // set an octal field, return true if the number fits - char *field = Get(id); + char *field = Get(id); char *p = field + Len(id); *--p = 0; while (p > field) { - *--p = '0' + (n & 7); + *--p = char('0' + (n & 7)); n >>= 3; } return n == 0; @@ -289,7 +291,10 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) size_t len = name.length(); wxCharBuffer approx(len); for (size_t i = 0; i < len; i++) - approx.data()[i] = name[i] & ~0x7F ? '_' : name[i]; + { + wxChar c = name[i]; + approx.data()[i] = c & ~0x7F ? '_' : c; + } nameBuf = approx; } @@ -309,7 +314,7 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) for (;;) { fits = i < maxprefix && len - i <= maxname; - + if (!fits) { const char *p = strchr(mbName + i, '/'); if (p) @@ -331,7 +336,7 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) return fits && !badconv; } - + ///////////////////////////////////////////////////////////////////////////// // Some helpers @@ -341,32 +346,101 @@ static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1) return ((size + chunk - 1) / chunk) * chunk; } -static wxString GroupName() -{ #ifdef __UNIX__ - group *gr; - if ((gr = getgrgid(getgid())) != NULL) - return wxString(gr->gr_name, wxConvLibc); + +static wxString wxTarUserName(int uid) +{ + struct passwd *ppw; + +#ifdef HAVE_GETPWUID_R +#if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX + long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l)); +#else + size_t bufsize = 1024; +#endif + wxCharBuffer buf(bufsize); + struct passwd pw; + + memset(&pw, 0, sizeof(pw)); + if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name) + return wxString(pw.pw_name, wxConvLibc); +#else + if ((ppw = getpwuid(uid)) != NULL) + return wxString(ppw->pw_name, wxConvLibc); #endif return _("unknown"); } -static inline int UserId() +static wxString wxTarGroupName(int gid) { -#ifdef __UNIX__ - return getuid(); + struct group *pgr; +#ifdef HAVE_GETGRGID_R +#if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX + long grsize = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l)); +#else + size_t bufsize = 1024; +#endif + wxCharBuffer buf(bufsize); + struct group gr; + + memset(&gr, 0, sizeof(gr)); + if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name) + return wxString(gr.gr_name, wxConvLibc); #else - return 0; + if ((pgr = getgrgid(gid)) != NULL) + return wxString(pgr->gr_name, wxConvLibc); #endif + return _("unknown"); } -static inline int GroupId() +#endif // __UNIX__ + +// Cache the user and group names since getting them can be expensive, +// get both names and ids at the same time. +// +struct wxTarUser +{ + wxTarUser(); + ~wxTarUser() { delete [] uname; delete [] gname; } + + int uid; + int gid; + + wxChar *uname; + wxChar *gname; +}; + +wxTarUser::wxTarUser() { #ifdef __UNIX__ - return getgid(); + uid = getuid(); + gid = getgid(); + wxString usr = wxTarUserName(uid); + wxString grp = wxTarGroupName(gid); #else - return 0; + uid = 0; + gid = 0; + wxString usr = wxGetUserId(); + wxString grp = _("unknown"); +#endif + + uname = new wxChar[usr.length() + 1]; + wxStrcpy(uname, usr.c_str()); + + gname = new wxChar[grp.length() + 1]; + wxStrcpy(gname, grp.c_str()); +} + +static const wxTarUser& wxGetTarUser() +{ +#if wxUSE_THREADS + static wxCriticalSection cs; + wxCriticalSectionLocker lock(cs); #endif + static wxTarUser tu; + return tu; } // ignore the size field for entry types 3, 4, 5 and 6 @@ -381,7 +455,7 @@ static inline wxFileOffset GetDataSize(const wxTarEntry& entry) return 0; default: return entry.GetSize(); - }; + } } @@ -394,14 +468,14 @@ wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/, wxFileOffset size /*=0*/) : m_Mode(0644), m_IsModeSet(false), - m_UserId(UserId()), - m_GroupId(GroupId()), + m_UserId(wxGetTarUser().uid), + m_GroupId(wxGetTarUser().gid), m_Size(size), m_Offset(wxInvalidOffset), m_ModifyTime(dt), m_TypeFlag(wxTAR_REGTYPE), - m_UserName(wxGetUserId()), - m_GroupName(GroupName()), + m_UserName(wxGetTarUser().uname), + m_GroupName(wxGetTarUser().gname), m_DevMajor(~0), m_DevMinor(~0) { @@ -414,7 +488,8 @@ wxTarEntry::~wxTarEntry() } wxTarEntry::wxTarEntry(const wxTarEntry& e) - : m_Name(e.m_Name), + : wxArchiveEntry(), + m_Name(e.m_Name), m_Mode(e.m_Mode), m_IsModeSet(e.m_IsModeSet), m_UserId(e.m_UserId), @@ -529,14 +604,14 @@ wxString wxTarEntry::GetInternalName(const wxString& name, bool wxTarEntry::IsDir() const { - return m_TypeFlag - wxTAR_DIRTYPE == 0; + return m_TypeFlag == wxTAR_DIRTYPE; } void wxTarEntry::SetIsDir(bool isDir) { if (isDir) m_TypeFlag = wxTAR_DIRTYPE; - else if (m_TypeFlag - wxTAR_DIRTYPE == 0) + else if (m_TypeFlag == wxTAR_DIRTYPE) m_TypeFlag = wxTAR_REGTYPE; } @@ -554,7 +629,7 @@ int wxTarEntry::GetMode() const return m_Mode; else return m_Mode | 0111; - + } void wxTarEntry::SetMode(int mode) @@ -825,8 +900,8 @@ wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) { wxTarNumber n = 0; - const wxChar *p = value; - while (*p == ' ') + wxString::const_iterator p = value.begin(); + while (*p == ' ' && p != value.end()) p++; while (isdigit(*p)) n = n * 10 + (*p++ - '0'); @@ -870,13 +945,13 @@ bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) size_t recPos, recSize; bool ok = true; - for (recPos = 0; recPos < len; recPos += recSize) { + 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(*p)) + while (isdigit((unsigned char) *p)) recSize = recSize * 10 + *p++ - '0'; // validity checks @@ -910,7 +985,7 @@ bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) if (value.empty()) recs->erase(key); else - (*recs)[key] = value; + (*recs)[key] = value; } if (!ok || recPos < len || size != lastread) { @@ -959,7 +1034,7 @@ size_t wxTarInputStream::OnSysRead(void *buffer, size_t size) size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead(); m_pos += lastread; - + if (m_pos >= m_size) { m_lasterror = wxSTREAM_EOF; } else if (!m_parent_i_stream->IsOk()) { @@ -1010,12 +1085,12 @@ void wxTarOutputStream::Init(wxTarFormat format) m_extendedHdr = NULL; m_extendedSize = 0; m_lasterror = m_parent_o_stream->GetLastError(); + m_endrecWritten = false; } wxTarOutputStream::~wxTarOutputStream() { - if (m_tarsize) - Close(); + Close(); delete m_hdr; delete m_hdr2; delete [] m_extendedHdr; @@ -1048,10 +1123,10 @@ bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry) wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE, wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0 }; - char typeflag = e->GetTypeFlag(); + int typeflag = e->GetTypeFlag(); // pax does now allow data for wxTAR_LNKTYPE - if (!m_pax || typeflag - wxTAR_LNKTYPE != 0) + if (!m_pax || typeflag != wxTAR_LNKTYPE) if (strchr(nodata, typeflag) != NULL) CloseEntry(); } @@ -1134,7 +1209,7 @@ bool wxTarOutputStream::CloseEntry() bool wxTarOutputStream::Close() { - if (!CloseEntry()) + if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten)) return false; memset(m_hdr, 0, sizeof(*m_hdr)); @@ -1146,6 +1221,7 @@ bool wxTarOutputStream::Close() m_tarsize = 0; m_tarstart = wxInvalidOffset; m_lasterror = m_parent_o_stream->GetLastError(); + m_endrecWritten = true; return IsOk(); } @@ -1161,7 +1237,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) if (entry.GetSize() == wxInvalidOffset) entry.SetSize(0); - m_large = SetHeaderNumber(TAR_SIZE, entry.GetSize()); + m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize()); SetHeaderDate(_T("mtime"), entry.GetDateTime()); if (entry.GetAccessTime().IsValid()) @@ -1169,10 +1245,10 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) if (entry.GetCreateTime().IsValid()) SetHeaderDate(_T("ctime"), entry.GetCreateTime()); - *m_hdr->Get(TAR_TYPEFLAG) = entry.GetTypeFlag(); + *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag()); strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC); - strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); + strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); SetHeaderString(TAR_LINKNAME, entry.GetLinkName()); SetHeaderString(TAR_UNAME, entry.GetUserName()); @@ -1181,7 +1257,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) if (~entry.GetDevMajor()) SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor()); if (~entry.GetDevMinor()) - SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); + SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); m_chksum = m_hdr->Sum(); m_hdr->SetOctal(TAR_CHKSUM, m_chksum); @@ -1212,7 +1288,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) 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_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)); @@ -1236,7 +1312,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) 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(); @@ -1250,7 +1326,7 @@ wxString wxTarOutputStream::PaxHeaderPath(const wxString& format, wxString d = path.BeforeLast(_T('/')); wxString f = path.AfterLast(_T('/')); wxString ret; - + if (d.empty()) d = _T("."); @@ -1264,7 +1340,7 @@ wxString wxTarOutputStream::PaxHeaderPath(const wxString& format, if (end == wxString::npos || end + 1 >= format.length()) break; ret << format.substr(begin, end - begin); - switch (format[end + 1]) { + switch ( format[end + 1].GetValue() ) { case 'd': ret << d; break; case 'f': ret << f; break; case 'p': ret << wxGetProcessId(); break; @@ -1339,7 +1415,8 @@ void wxTarOutputStream::SetHeaderDate(const wxString& key, wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0); wxLongLong secs = ll / 1000L; - if (key != _T("mtime") || !m_hdr->SetOctal(TAR_MTIME, secs.GetValue()) + if (key != _T("mtime") + || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue())) || secs <= 0 || secs >= 0x7fffffff) { wxString str; @@ -1357,11 +1434,16 @@ 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];