]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/tarstrm.cpp
updated wxExecute checks in wxGTK to be same as in other Unix ports after recent...
[wxWidgets.git] / src / common / tarstrm.cpp
index cf149f638a898045f04dbaeb0dccefd5420621ce..7b053df2ab38d5f17a83553e7c2527e54cea252b 100644 (file)
 #include "wx/datetime.h"
 #include "wx/ptr_scpd.h"
 #include "wx/filename.h"
+#include "wx/thread.h"
 
 #include <ctype.h>
 
 #ifdef __UNIX__
+#include <pwd.h>
 #include <grp.h>
 #endif
 
@@ -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);
 }
@@ -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;
     }
 
@@ -341,32 +346,99 @@ 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;
+
+    if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0)
+        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;
+
+    if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0)
+        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
@@ -394,14 +466,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)
 {
@@ -824,10 +896,10 @@ wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const
 {
     wxString value;
 
-    if ((value = GetExtendedHeader(wxTarHeaderBlock::Name(id))) != wxEmptyString) {
+    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');
@@ -841,7 +913,7 @@ wxString wxTarInputStream::GetHeaderString(int id) const
 {
     wxString value;
 
-    if ((value = GetExtendedHeader(wxTarHeaderBlock::Name(id))) != wxEmptyString)
+    if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString)
         return value;
 
     return wxString(m_hdr->Get(id), GetConv());
@@ -1011,12 +1083,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;
@@ -1135,9 +1207,9 @@ bool wxTarOutputStream::CloseEntry()
 
 bool wxTarOutputStream::Close()
 {
-    if (!CloseEntry())
+    if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten))
         return false;
-
     memset(m_hdr, 0, sizeof(*m_hdr));
     int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor)
                     - m_tarsize) / TAR_BLOCKSIZE;
@@ -1147,6 +1219,7 @@ bool wxTarOutputStream::Close()
     m_tarsize = 0;
     m_tarstart = wxInvalidOffset;
     m_lasterror = m_parent_o_stream->GetLastError();
+    m_endrecWritten = true;
     return IsOk();
 }
 
@@ -1265,7 +1338,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;
@@ -1291,7 +1364,7 @@ bool wxTarOutputStream::ModifyHeader()
         originalPos = m_parent_o_stream->TellO();
         if (originalPos != wxInvalidOffset)
             sizePos =
-                m_parent_o_stream->SeekO(m_headpos + wxTarHeaderBlock::Offset(TAR_SIZE));
+                m_parent_o_stream->SeekO(m_headpos + m_hdr->Offset(TAR_SIZE));
     }
 
     if (sizePos == wxInvalidOffset || !m_hdr->SetOctal(TAR_SIZE, m_pos)) {
@@ -1302,7 +1375,7 @@ bool wxTarOutputStream::ModifyHeader()
 
     m_chksum += m_hdr->SumField(TAR_SIZE);
     m_hdr->SetOctal(TAR_CHKSUM, m_chksum);
-    wxFileOffset sumPos = m_headpos + wxTarHeaderBlock::Offset(TAR_CHKSUM);
+    wxFileOffset sumPos = m_headpos + m_hdr->Offset(TAR_CHKSUM);
 
     return
         m_hdr->WriteField(*m_parent_o_stream, TAR_SIZE) &&
@@ -1322,16 +1395,16 @@ bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n)
     if (m_hdr->SetOctal(id, n)) {
         return true;
     } else {
-        SetExtendedHeader(wxTarHeaderBlock::Name(id), wxLongLong(n).ToString());
+        SetExtendedHeader(m_hdr->Name(id), wxLongLong(n).ToString());
         return false;
     }
 }
 
 void wxTarOutputStream::SetHeaderString(int id, const wxString& str)
 {
-    strncpy(m_hdr->Get(id), str.mb_str(GetConv()), wxTarHeaderBlock::Len(id));
-    if (str.length() > wxTarHeaderBlock::Len(id))
-        SetExtendedHeader(wxTarHeaderBlock::Name(id), str);
+    strncpy(m_hdr->Get(id), str.mb_str(GetConv()), m_hdr->Len(id));
+    if (str.length() > m_hdr->Len(id))
+        SetExtendedHeader(m_hdr->Name(id), str);
 }
 
 void wxTarOutputStream::SetHeaderDate(const wxString& key,
@@ -1359,11 +1432,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];