#include "wx/tarstrm.h"
#ifndef WX_PRECOMP
- #include "wx/hashmap.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/utils.h"
#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
};
enum {
- TAR_BLOCKSIZE = 512,
+ TAR_BLOCKSIZE = 512
};
// checksum type
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;
}
}
static void check();
};
-wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock);
+wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock)
// A table giving the field names and offsets in a tar header block
const wxTarField wxTarHeaderBlock::fields[] =
void wxTarHeaderBlock::check()
{
+#if 0
wxCOMPILE_TIME_ASSERT(
WXSIZEOF(fields) == TAR_NUMFIELDS + 1,
Wrong_number_of_elements_in_fields_table
);
+#endif
}
bool wxTarHeaderBlock::IsAllZeros() const
}
bool wxTarHeaderBlock::Read(wxInputStream& in)
-{
+{
bool ok = true;
for (int id = 0; id < TAR_NUMFIELDS && ok; id++)
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);
}
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;
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;
}
for (;;) {
fits = i < maxprefix && len - i <= maxname;
-
+
if (!fits) {
const char *p = strchr(mbName + i, '/');
if (p)
return fits && !badconv;
}
-
+
/////////////////////////////////////////////////////////////////////////////
// Some helpers
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
return 0;
default:
return entry.GetSize();
- };
+ }
}
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)
{
}
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),
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;
}
return m_Mode;
else
return m_Mode | 0111;
-
+
}
void wxTarEntry::SetMode(int mode)
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');
// 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
if (value.empty())
recs->erase(key);
else
- (*recs)[key] = value;
+ (*recs)[key] = value;
}
if (!ok || recPos < len || size != 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()) {
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;
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();
}
bool wxTarOutputStream::Close()
{
- if (!CloseEntry())
+ if (!CloseEntry() || (m_tarsize == 0 && m_endrecWritten))
return false;
memset(m_hdr, 0, sizeof(*m_hdr));
m_tarsize = 0;
m_tarstart = wxInvalidOffset;
m_lasterror = m_parent_o_stream->GetLastError();
+ m_endrecWritten = true;
return IsOk();
}
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())
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());
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);
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));
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();
wxString d = path.BeforeLast(_T('/'));
wxString f = path.AfterLast(_T('/'));
wxString ret;
-
+
if (d.empty())
d = _T(".");
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;
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;
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];