diff options
Diffstat (limited to 'CPP/7zip/Archive/Tar/TarOut.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Tar/TarOut.cpp | 230 |
1 files changed, 138 insertions, 92 deletions
diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp index 6e699e28..51081e8b 100755..100644 --- a/CPP/7zip/Archive/Tar/TarOut.cpp +++ b/CPP/7zip/Archive/Tar/TarOut.cpp @@ -2,8 +2,6 @@ #include "StdAfx.h" -#include "Common/IntToString.h" - #include "../../Common/StreamUtils.h" #include "TarOut.h" @@ -11,26 +9,15 @@ namespace NArchive { namespace NTar { -HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size) -{ - return WriteStream(m_Stream, buffer, size); -} - -void COutArchive::Create(ISequentialOutStream *outStream) -{ - m_Stream = outStream; -} - -static AString MakeOctalString(UInt64 value) +HRESULT COutArchive::WriteBytes(const void *data, unsigned size) { - char s[32]; - ConvertUInt64ToString(value, s, 8); - return AString(s) + ' '; + Pos += size; + return WriteStream(m_Stream, data, size); } -static void MyStrNCpy(char *dest, const char *src, int size) +static void MyStrNCpy(char *dest, const char *src, unsigned size) { - for (int i = 0; i < size; i++) + for (unsigned i = 0; i < size; i++) { char c = src[i]; dest[i] = c; @@ -39,54 +26,53 @@ static void MyStrNCpy(char *dest, const char *src, int size) } } -static bool MakeOctalString8(char *s, UInt32 value) +static bool WriteOctal_8(char *s, UInt32 val) { - AString tempString = MakeOctalString(value); - - const int kMaxSize = 8; - if (tempString.Length() >= kMaxSize) + const unsigned kNumDigits = 8 - 1; + if (val >= ((UInt32)1 << (kNumDigits * 3))) return false; - int numSpaces = kMaxSize - (tempString.Length() + 1); - for (int i = 0; i < numSpaces; i++) - s[i] = ' '; - MyStringCopy(s + numSpaces, (const char *)tempString); + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } return true; } -static void MakeOctalString12(char *s, UInt64 value) +static void WriteOctal_12(char *s, UInt64 val) { - AString tempString = MakeOctalString(value); - const int kMaxSize = 12; - if (tempString.Length() > kMaxSize) + const unsigned kNumDigits = 12 - 1; + if (val >= ((UInt64)1 << (kNumDigits * 3))) { // GNU extension; s[0] = (char)(Byte)0x80; s[1] = s[2] = s[3] = 0; - for (int i = 0; i < 8; i++, value <<= 8) - s[4 + i] = (char)(value >> 56); + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[4 + i] = (char)(val >> 56); return; } - int numSpaces = kMaxSize - tempString.Length(); - for (int i = 0; i < numSpaces; i++) - s[i] = ' '; - memmove(s + numSpaces, (const char *)tempString, tempString.Length()); + for (unsigned i = 0; i < kNumDigits; i++) + { + s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); + val >>= 3; + } } -static void MakeOctalString12_From_Int64(char *s, Int64 value) +static void WriteOctal_12_Signed(char *s, Int64 val) { - if (value >= 0) + if (val >= 0) { - MakeOctalString12(s, value); + WriteOctal_12(s, val); return; } s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF; - for (int i = 0; i < 8; i++, value <<= 8) - s[4 + i] = (char)(value >> 56); + for (unsigned i = 0; i < 8; i++, val <<= 8) + s[4 + i] = (char)(val >> 56); } -static bool CopyString(char *dest, const AString &src, int maxSize) +static bool CopyString(char *dest, const AString &src, unsigned maxSize) { - if (src.Length() >= maxSize) + if (src.Len() >= maxSize) return false; MyStringCopy(dest, (const char *)src); return true; @@ -97,25 +83,22 @@ static bool CopyString(char *dest, const AString &src, int maxSize) HRESULT COutArchive::WriteHeaderReal(const CItem &item) { char record[NFileHeader::kRecordSize]; + memset(record, 0, NFileHeader::kRecordSize); char *cur = record; - int i; - for (i = 0; i < NFileHeader::kRecordSize; i++) - record[i] = 0; - // RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize)); - if (item.Name.Length() > NFileHeader::kNameSize) + if (item.Name.Len() > NFileHeader::kNameSize) return E_FAIL; MyStrNCpy(cur, item.Name, NFileHeader::kNameSize); cur += NFileHeader::kNameSize; - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8; - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8; - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8; + RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8; - MakeOctalString12(cur, item.PackSize); cur += 12; - MakeOctalString12_From_Int64(cur, item.MTime); cur += 12; + WriteOctal_12(cur, item.PackSize); cur += 12; + WriteOctal_12_Signed(cur, item.MTime); cur += 12; - memmove(cur, NFileHeader::kCheckSumBlanks, 8); + memset(cur, ' ', 8); cur += 8; *cur++ = item.LinkFlag; @@ -123,7 +106,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize)); cur += NFileHeader::kNameSize; - memmove(cur, item.Magic, 8); + memcpy(cur, item.Magic, 8); cur += 8; RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize)); @@ -132,64 +115,127 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item) cur += NFileHeader::kGroupNameSize; - if (item.DeviceMajorDefined) - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor)); - cur += 8; + if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8; + if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8; - if (item.DeviceMinorDefined) - RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor)); - cur += 8; + if (item.IsSparse()) + { + record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); + WriteOctal_12(record + 483, item.Size); + for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + char *p = record + 386 + 24 * i; + WriteOctal_12(p, sb.Offset); + WriteOctal_12(p + 12, sb.Size); + } + } + { + UInt32 checkSum = 0; + { + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + checkSum += (Byte)record[i]; + } + /* we use GNU TAR scheme: + checksum field is formatted differently from the + other fields: it has [6] digits, a null, then a space. */ + // RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum)); + const unsigned kNumDigits = 6; + for (unsigned i = 0; i < kNumDigits; i++) + { + record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); + checkSum >>= 3; + } + record[148 + 6] = 0; + } - UInt32 checkSumReal = 0; - for (i = 0; i < NFileHeader::kRecordSize; i++) - checkSumReal += Byte(record[i]); + RINOK(WriteBytes(record, NFileHeader::kRecordSize)); - RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal)); + if (item.IsSparse()) + { + for (unsigned i = 4; i < item.SparseBlocks.Size();) + { + memset(record, 0, NFileHeader::kRecordSize); + for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++) + { + const CSparseBlock &sb = item.SparseBlocks[i]; + char *p = record + 24 * t; + WriteOctal_12(p, sb.Offset); + WriteOctal_12(p + 12, sb.Size); + } + record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); + RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + } + } - return WriteBytes(record, NFileHeader::kRecordSize); + return S_OK; } HRESULT COutArchive::WriteHeader(const CItem &item) { - int nameSize = item.Name.Length(); - if (nameSize < NFileHeader::kNameSize) + unsigned nameSize = item.Name.Len(); + unsigned linkSize = item.LinkName.Len(); + + /* There two versions of GNU tar: + OLDGNU_FORMAT: it writes short name and zero at the end + GNU_FORMAT: it writes only short name without zero at the end + we write it as OLDGNU_FORMAT with zero at the end */ + + if (nameSize < NFileHeader::kNameSize && + linkSize < NFileHeader::kNameSize) return WriteHeaderReal(item); - CItem modifiedItem = item; - int nameStreamSize = nameSize + 1; - modifiedItem.PackSize = nameStreamSize; - modifiedItem.LinkFlag = 'L'; - modifiedItem.Name = NFileHeader::kLongLink; - modifiedItem.LinkName.Empty(); - RINOK(WriteHeaderReal(modifiedItem)); - RINOK(WriteBytes(item.Name, nameStreamSize)); - RINOK(FillDataResidual(nameStreamSize)); - - modifiedItem = item; - modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1); - return WriteHeaderReal(modifiedItem); + CItem mi = item; + mi.Name = NFileHeader::kLongLink; + mi.LinkName.Empty(); + for (int i = 0; i < 2; i++) + { + const AString *name; + // We suppose that GNU tar also writes item for long link before item for LongName? + if (i == 0) + { + mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink; + name = &item.LinkName; + } + else + { + mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; + name = &item.Name; + } + if (name->Len() < NFileHeader::kNameSize) + continue; + unsigned nameStreamSize = name->Len() + 1; + mi.PackSize = nameStreamSize; + RINOK(WriteHeaderReal(mi)); + RINOK(WriteBytes((const char *)*name, nameStreamSize)); + RINOK(FillDataResidual(nameStreamSize)); + } + + mi = item; + if (mi.Name.Len() >= NFileHeader::kNameSize) + mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1); + if (mi.LinkName.Len() >= NFileHeader::kNameSize) + mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1); + return WriteHeaderReal(mi); } HRESULT COutArchive::FillDataResidual(UInt64 dataSize) { - UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1)); + unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1)); if (lastRecordSize == 0) return S_OK; - UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize; - Byte residualBytes[NFileHeader::kRecordSize]; - for (UInt32 i = 0; i < residualSize; i++) - residualBytes[i] = 0; - return WriteBytes(residualBytes, residualSize); + unsigned rem = NFileHeader::kRecordSize - lastRecordSize; + Byte buf[NFileHeader::kRecordSize]; + memset(buf, 0, rem); + return WriteBytes(buf, rem); } HRESULT COutArchive::WriteFinishHeader() { Byte record[NFileHeader::kRecordSize]; - int i; - for (i = 0; i < NFileHeader::kRecordSize; i++) - record[i] = 0; - for (i = 0; i < 2; i++) + memset(record, 0, NFileHeader::kRecordSize); + for (unsigned i = 0; i < 2; i++) { RINOK(WriteBytes(record, NFileHeader::kRecordSize)); } |