]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/tarstrm.cpp
fixed wxXmlResource::Load's detection of filenames to be done as early as possible
[wxWidgets.git] / src / common / tarstrm.cpp
index 65a4099d41f59149b176167466a8248025dc4040..033c34cf093a688d52a79b04effb627fb884304c 100644 (file)
 
 #include "wx/buffer.h"
 #include "wx/datetime.h"
 
 #include "wx/buffer.h"
 #include "wx/datetime.h"
-#include "wx/ptr_scpd.h"
+#include "wx/scopedptr.h"
 #include "wx/filename.h"
 #include "wx/filename.h"
+#include "wx/thread.h"
 
 #include <ctype.h>
 
 #ifdef __UNIX__
 
 #include <ctype.h>
 
 #ifdef __UNIX__
+#include <pwd.h>
 #include <grp.h>
 #endif
 
 #include <grp.h>
 #endif
 
@@ -228,7 +230,7 @@ wxUint32 wxTarHeaderBlock::SumField(int id)
 }
 
 bool wxTarHeaderBlock::Read(wxInputStream& in)
 }
 
 bool wxTarHeaderBlock::Read(wxInputStream& in)
-{   
+{
     bool ok = true;
 
     for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
     bool ok = true;
 
     for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
@@ -266,7 +268,7 @@ wxTarNumber wxTarHeaderBlock::GetOctal(int id)
 bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n)
 {
     // set an octal field, return true if the number fits
 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) {
     char *p = field + Len(id);
     *--p = 0;
     while (p > field) {
@@ -312,7 +314,7 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv)
 
     for (;;) {
         fits = i < maxprefix && len - i <= maxname;
 
     for (;;) {
         fits = i < maxprefix && len - i <= maxname;
-        
+
         if (!fits) {
             const char *p = strchr(mbName + i, '/');
             if (p)
         if (!fits) {
             const char *p = strchr(mbName + i, '/');
             if (p)
@@ -334,7 +336,7 @@ bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv)
     return fits && !badconv;
 }
 
     return fits && !badconv;
 }
 
-    
+
 /////////////////////////////////////////////////////////////////////////////
 // Some helpers
 
 /////////////////////////////////////////////////////////////////////////////
 // Some helpers
 
@@ -344,32 +346,101 @@ static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1)
     return ((size + chunk - 1) / chunk) * chunk;
 }
 
     return ((size + chunk - 1) / chunk) * chunk;
 }
 
-static wxString GroupName()
-{
 #ifdef __UNIX__
 #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");
 }
 
 #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
 #else
-    return 0;
+    size_t bufsize = 1024;
 #endif
 #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
+    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__
 {
 #ifdef __UNIX__
-    return getgid();
+    uid = getuid();
+    gid = getgid();
+    wxString usr = wxTarUserName(uid);
+    wxString grp = wxTarGroupName(gid);
 #else
 #else
-    return 0;
+    uid = 0;
+    gid = 0;
+    wxString usr = wxGetUserId();
+    wxString grp = _("unknown");
 #endif
 #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
 }
 
 // ignore the size field for entry types 3, 4, 5 and 6
@@ -397,14 +468,14 @@ wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/,
                        wxFileOffset size    /*=0*/)
   : m_Mode(0644),
     m_IsModeSet(false),
                        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_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)
 {
     m_DevMajor(~0),
     m_DevMinor(~0)
 {
@@ -558,7 +629,7 @@ int wxTarEntry::GetMode() const
         return m_Mode;
     else
         return m_Mode | 0111;
         return m_Mode;
     else
         return m_Mode | 0111;
-    
+
 }
 
 void wxTarEntry::SetMode(int mode)
 }
 
 void wxTarEntry::SetMode(int mode)
@@ -874,13 +945,13 @@ bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs)
     size_t recPos, recSize;
     bool ok = true;
 
     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;
         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
             recSize = recSize * 10 + *p++ - '0';
 
         // validity checks
@@ -914,7 +985,7 @@ bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs)
         if (value.empty())
             recs->erase(key);
         else
         if (value.empty())
             recs->erase(key);
         else
-            (*recs)[key] = value; 
+            (*recs)[key] = value;
     }
 
     if (!ok || recPos < len || size != lastread) {
     }
 
     if (!ok || recPos < len || size != lastread) {
@@ -963,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;
 
     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()) {
     if (m_pos >= m_size) {
         m_lasterror = wxSTREAM_EOF;
     } else if (!m_parent_i_stream->IsOk()) {
@@ -1014,12 +1085,12 @@ void wxTarOutputStream::Init(wxTarFormat format)
     m_extendedHdr = NULL;
     m_extendedSize = 0;
     m_lasterror = m_parent_o_stream->GetLastError();
     m_extendedHdr = NULL;
     m_extendedSize = 0;
     m_lasterror = m_parent_o_stream->GetLastError();
+    m_endrecWritten = false;
 }
 
 wxTarOutputStream::~wxTarOutputStream()
 {
 }
 
 wxTarOutputStream::~wxTarOutputStream()
 {
-    if (m_tarsize)
-        Close();
+    Close();
     delete m_hdr;
     delete m_hdr2;
     delete [] m_extendedHdr;
     delete m_hdr;
     delete m_hdr2;
     delete [] m_extendedHdr;
@@ -1138,7 +1209,7 @@ bool wxTarOutputStream::CloseEntry()
 
 bool wxTarOutputStream::Close()
 {
 
 bool wxTarOutputStream::Close()
 {
-    if (!CloseEntry())
+    if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten))
         return false;
 
     memset(m_hdr, 0, sizeof(*m_hdr));
         return false;
 
     memset(m_hdr, 0, sizeof(*m_hdr));
@@ -1150,6 +1221,7 @@ bool wxTarOutputStream::Close()
     m_tarsize = 0;
     m_tarstart = wxInvalidOffset;
     m_lasterror = m_parent_o_stream->GetLastError();
     m_tarsize = 0;
     m_tarstart = wxInvalidOffset;
     m_lasterror = m_parent_o_stream->GetLastError();
+    m_endrecWritten = true;
     return IsOk();
 }
 
     return IsOk();
 }
 
@@ -1176,7 +1248,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
     *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag());
 
     strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC);
     *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());
 
     SetHeaderString(TAR_LINKNAME, entry.GetLinkName());
     SetHeaderString(TAR_UNAME, entry.GetUserName());
@@ -1185,7 +1257,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
     if (~entry.GetDevMajor())
         SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor());
     if (~entry.GetDevMinor())
     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);
 
     m_chksum = m_hdr->Sum();
     m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
@@ -1216,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_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));
 
         strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME));
         strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME));
 
@@ -1240,7 +1312,7 @@ bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry)
                      m_badfit.c_str(), entry.GetName().c_str());
         m_badfit.clear();
     }
                      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();
     m_hdr->Write(*m_parent_o_stream);
     m_tarsize += TAR_BLOCKSIZE;
     m_lasterror = m_parent_o_stream->GetLastError();
@@ -1254,7 +1326,7 @@ wxString wxTarOutputStream::PaxHeaderPath(const wxString& format,
     wxString d = path.BeforeLast(_T('/'));
     wxString f = path.AfterLast(_T('/'));
     wxString ret;
     wxString d = path.BeforeLast(_T('/'));
     wxString f = path.AfterLast(_T('/'));
     wxString ret;
-    
+
     if (d.empty())
         d = _T(".");
 
     if (d.empty())
         d = _T(".");