rlm@1
|
1 // Archive/TarIn.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "TarIn.h"
|
rlm@1
|
6 #include "TarHeader.h"
|
rlm@1
|
7
|
rlm@1
|
8 #include "Common/StringToInt.h"
|
rlm@1
|
9 #include "Windows/Defs.h"
|
rlm@1
|
10
|
rlm@1
|
11 #include "../../Common/StreamUtils.h"
|
rlm@1
|
12
|
rlm@1
|
13 namespace NArchive {
|
rlm@1
|
14 namespace NTar {
|
rlm@1
|
15
|
rlm@1
|
16 static void MyStrNCpy(char *dest, const char *src, int size)
|
rlm@1
|
17 {
|
rlm@1
|
18 for (int i = 0; i < size; i++)
|
rlm@1
|
19 {
|
rlm@1
|
20 char c = src[i];
|
rlm@1
|
21 dest[i] = c;
|
rlm@1
|
22 if (c == 0)
|
rlm@1
|
23 break;
|
rlm@1
|
24 }
|
rlm@1
|
25 }
|
rlm@1
|
26
|
rlm@1
|
27 static bool OctalToNumber(const char *srcString, int size, UInt64 &res)
|
rlm@1
|
28 {
|
rlm@1
|
29 char sz[32];
|
rlm@1
|
30 MyStrNCpy(sz, srcString, size);
|
rlm@1
|
31 sz[size] = 0;
|
rlm@1
|
32 const char *end;
|
rlm@1
|
33 int i;
|
rlm@1
|
34 for (i = 0; sz[i] == ' '; i++);
|
rlm@1
|
35 res = ConvertOctStringToUInt64(sz + i, &end);
|
rlm@1
|
36 return (*end == ' ' || *end == 0);
|
rlm@1
|
37 }
|
rlm@1
|
38
|
rlm@1
|
39 static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
|
rlm@1
|
40 {
|
rlm@1
|
41 UInt64 res64;
|
rlm@1
|
42 if (!OctalToNumber(srcString, size, res64))
|
rlm@1
|
43 return false;
|
rlm@1
|
44 res = (UInt32)res64;
|
rlm@1
|
45 return (res64 <= 0xFFFFFFFF);
|
rlm@1
|
46 }
|
rlm@1
|
47
|
rlm@1
|
48 #define RIF(x) { if (!(x)) return S_FALSE; }
|
rlm@1
|
49
|
rlm@1
|
50 static bool IsRecordLast(const char *buf)
|
rlm@1
|
51 {
|
rlm@1
|
52 for (int i = 0; i < NFileHeader::kRecordSize; i++)
|
rlm@1
|
53 if (buf[i] != 0)
|
rlm@1
|
54 return false;
|
rlm@1
|
55 return true;
|
rlm@1
|
56 }
|
rlm@1
|
57
|
rlm@1
|
58 static void ReadString(const char *s, int size, AString &result)
|
rlm@1
|
59 {
|
rlm@1
|
60 char temp[NFileHeader::kRecordSize + 1];
|
rlm@1
|
61 MyStrNCpy(temp, s, size);
|
rlm@1
|
62 temp[size] = '\0';
|
rlm@1
|
63 result = temp;
|
rlm@1
|
64 }
|
rlm@1
|
65
|
rlm@1
|
66 static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, size_t &processedSize)
|
rlm@1
|
67 {
|
rlm@1
|
68 item.LongLinkSize = 0;
|
rlm@1
|
69 char buf[NFileHeader::kRecordSize];
|
rlm@1
|
70 char *p = buf;
|
rlm@1
|
71
|
rlm@1
|
72 filled = false;
|
rlm@1
|
73
|
rlm@1
|
74 processedSize = NFileHeader::kRecordSize;
|
rlm@1
|
75 RINOK(ReadStream(stream, buf, &processedSize));
|
rlm@1
|
76 if (processedSize == 0 || (processedSize == NFileHeader::kRecordSize && IsRecordLast(buf)))
|
rlm@1
|
77 return S_OK;
|
rlm@1
|
78 if (processedSize < NFileHeader::kRecordSize)
|
rlm@1
|
79 return S_FALSE;
|
rlm@1
|
80
|
rlm@1
|
81 ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
|
rlm@1
|
82
|
rlm@1
|
83 RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
|
rlm@1
|
84
|
rlm@1
|
85 if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
|
rlm@1
|
86 if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;
|
rlm@1
|
87
|
rlm@1
|
88 RIF(OctalToNumber(p, 12, item.Size)); p += 12;
|
rlm@1
|
89 RIF(OctalToNumber32(p, 12, item.MTime)); p += 12;
|
rlm@1
|
90
|
rlm@1
|
91 UInt32 checkSum;
|
rlm@1
|
92 RIF(OctalToNumber32(p, 8, checkSum));
|
rlm@1
|
93 memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8;
|
rlm@1
|
94
|
rlm@1
|
95 item.LinkFlag = *p++;
|
rlm@1
|
96
|
rlm@1
|
97 ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
|
rlm@1
|
98
|
rlm@1
|
99 memcpy(item.Magic, p, 8); p += 8;
|
rlm@1
|
100
|
rlm@1
|
101 ReadString(p, NFileHeader::kUserNameSize, item.UserName); p += NFileHeader::kUserNameSize;
|
rlm@1
|
102 ReadString(p, NFileHeader::kUserNameSize, item.GroupName); p += NFileHeader::kUserNameSize;
|
rlm@1
|
103
|
rlm@1
|
104 item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8;
|
rlm@1
|
105 item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8;
|
rlm@1
|
106
|
rlm@1
|
107 AString prefix;
|
rlm@1
|
108 ReadString(p, NFileHeader::kPrefixSize, prefix);
|
rlm@1
|
109 p += NFileHeader::kPrefixSize;
|
rlm@1
|
110 if (!prefix.IsEmpty() && item.IsMagic() &&
|
rlm@1
|
111 (item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
|
rlm@1
|
112 item.Name = prefix + AString('/') + item.Name;
|
rlm@1
|
113
|
rlm@1
|
114 if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
|
rlm@1
|
115 item.Size = 0;
|
rlm@1
|
116
|
rlm@1
|
117 UInt32 checkSumReal = 0;
|
rlm@1
|
118 for (int i = 0; i < NFileHeader::kRecordSize; i++)
|
rlm@1
|
119 checkSumReal += (Byte)buf[i];
|
rlm@1
|
120
|
rlm@1
|
121 if (checkSumReal != checkSum)
|
rlm@1
|
122 return S_FALSE;
|
rlm@1
|
123
|
rlm@1
|
124 filled = true;
|
rlm@1
|
125 return S_OK;
|
rlm@1
|
126 }
|
rlm@1
|
127
|
rlm@1
|
128 HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item)
|
rlm@1
|
129 {
|
rlm@1
|
130 size_t processedSize;
|
rlm@1
|
131 RINOK(GetNextItemReal(stream, filled, item, processedSize));
|
rlm@1
|
132 if (!filled)
|
rlm@1
|
133 return S_OK;
|
rlm@1
|
134 // GNUtar extension
|
rlm@1
|
135 if (item.LinkFlag == 'L')
|
rlm@1
|
136 {
|
rlm@1
|
137 if (item.Name.Compare(NFileHeader::kLongLink) != 0)
|
rlm@1
|
138 if (item.Name.Compare(NFileHeader::kLongLink2) != 0)
|
rlm@1
|
139 return S_FALSE;
|
rlm@1
|
140
|
rlm@1
|
141 AString fullName;
|
rlm@1
|
142 if (item.Size > (1 << 15))
|
rlm@1
|
143 return S_FALSE;
|
rlm@1
|
144 int packSize = (int)item.GetPackSize();
|
rlm@1
|
145 char *buffer = fullName.GetBuffer(packSize + 1);
|
rlm@1
|
146
|
rlm@1
|
147 RINOK(ReadStream_FALSE(stream, buffer, packSize));
|
rlm@1
|
148 processedSize += packSize;
|
rlm@1
|
149 buffer[item.Size] = '\0';
|
rlm@1
|
150 fullName.ReleaseBuffer();
|
rlm@1
|
151
|
rlm@1
|
152 UInt64 headerPosition = item.HeaderPosition;
|
rlm@1
|
153 {
|
rlm@1
|
154 size_t processedSize2;
|
rlm@1
|
155 RINOK(GetNextItemReal(stream, filled, item, processedSize2));
|
rlm@1
|
156 }
|
rlm@1
|
157 item.LongLinkSize = (unsigned)processedSize;
|
rlm@1
|
158 item.Name = fullName;
|
rlm@1
|
159 item.HeaderPosition = headerPosition;
|
rlm@1
|
160 }
|
rlm@1
|
161 else if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
|
rlm@1
|
162 {
|
rlm@1
|
163 // pax Extended Header
|
rlm@1
|
164 return S_OK;
|
rlm@1
|
165 }
|
rlm@1
|
166 else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
|
rlm@1
|
167 {
|
rlm@1
|
168 // GNU Extensions to the Archive Format
|
rlm@1
|
169 return S_OK;
|
rlm@1
|
170 }
|
rlm@1
|
171 else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
|
rlm@1
|
172 return S_FALSE;
|
rlm@1
|
173 return S_OK;
|
rlm@1
|
174 }
|
rlm@1
|
175
|
rlm@1
|
176 }}
|