// TarOut.cpp #include "StdAfx.h" #include "Common/IntToString.h" #include "../../Common/StreamUtils.h" #include "TarOut.h" 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) { char s[32]; ConvertUInt64ToString(value, s, 8); return AString(s) + ' '; } static void MyStrNCpy(char *dest, const char *src, int size) { for (int i = 0; i < size; i++) { char c = src[i]; dest[i] = c; if (c == 0) break; } } static bool MakeOctalString8(char *s, UInt32 value) { AString tempString = MakeOctalString(value); const int kMaxSize = 8; if (tempString.Length() >= kMaxSize) return false; int numSpaces = kMaxSize - (tempString.Length() + 1); for(int i = 0; i < numSpaces; i++) s[i] = ' '; MyStringCopy(s + numSpaces, (const char *)tempString); return true; } static void MakeOctalString12(char *s, UInt64 value) { AString tempString = MakeOctalString(value); const int kMaxSize = 12; if (tempString.Length() > kMaxSize) { // 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); return; } int numSpaces = kMaxSize - tempString.Length(); for(int i = 0; i < numSpaces; i++) s[i] = ' '; memmove(s + numSpaces, (const char *)tempString, tempString.Length()); } static bool CopyString(char *dest, const AString &src, int maxSize) { if (src.Length() >= maxSize) return false; MyStringCopy(dest, (const char *)src); return true; } #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; } HRESULT COutArchive::WriteHeaderReal(const CItem &item) { char record[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) 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; MakeOctalString12(cur, item.Size); cur += 12; MakeOctalString12(cur, item.MTime); cur += 12; memmove(cur, NFileHeader::kCheckSumBlanks, 8); cur += 8; *cur++ = item.LinkFlag; RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize)); cur += NFileHeader::kNameSize; memmove(cur, item.Magic, 8); cur += 8; RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize)); cur += NFileHeader::kUserNameSize; RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize)); cur += NFileHeader::kGroupNameSize; if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor)); cur += 8; if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor)); cur += 8; UInt32 checkSumReal = 0; for(i = 0; i < NFileHeader::kRecordSize; i++) checkSumReal += Byte(record[i]); RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal)); return WriteBytes(record, NFileHeader::kRecordSize); } HRESULT COutArchive::WriteHeader(const CItem &item) { int nameSize = item.Name.Length(); if (nameSize < NFileHeader::kNameSize) return WriteHeaderReal(item); CItem modifiedItem = item; int nameStreamSize = nameSize + 1; modifiedItem.Size = 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); } HRESULT COutArchive::FillDataResidual(UInt64 dataSize) { UInt32 lastRecordSize = UInt32(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); } 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++) { RINOK(WriteBytes(record, NFileHeader::kRecordSize)); } return S_OK; } }}