.h

flame_ustar.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/*
* File: ustar.h
*
*
* Created on 2021年4月9日, 上午9:57
*/

#ifndef USTAR_H
#define USTAR_H

#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <tar.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <sys/stat.h>

#include "flame.h"


#pragma pack(1) //一字节对齐

/*
* This is the ustar (Posix 1003.1) header.
*/
typedef struct _flame_ustar_header
{
char name[100]; /* 0 Dateiname */
char mode[8]; /* 100 Zugriffsrechte */
char uid[8]; /* 108 Benutzernummer */
char gid[8]; /* 116 Benutzergruppe */
char size[12]; /* 124 Dateigroesze */
char mtime[12]; /* 136 Zeit d. letzten Aenderung */
char chksum[8]; /* 148 Checksumme */
char typeflag; /* 156 Typ der Datei */
char linkname[100]; /* 157 Zielname des Links */
char magic[TMAGLEN]; /* 257 "ustar" */
char version[TVERSLEN]; /* 263 Version v. star */
char uname[32]; /* 265 Benutzername */
char gname[32]; /* 297 Gruppenname */
char devmajor[8]; /* 329 Major bei Geraeten */
char devminor[8]; /* 337 Minor bei Geraeten */
char prefix[155]; /* 345 Prefix fuer t_name */
/* 500 Ende */
char mfill[12]; /* 500 Filler bis 512 */
} FlameUstarHeader;

/**/
#define FLAME_USTAR_TABLE_SIZE sizeof(FlameUstarHeader)
/*
* gnu tar extensions:
*/

#define FLAME_USTAR_LONGNAME_MAGIC "././@LongLink"
#define FLAME_USTAR_LONGNAME_MAGIC_LEN 14 /* including NULL byte */
#define FLAME_USTAR_LONGLINK_TYPE 'K' /* Identifies the NEXT file on the tape as having a long linkname */
#define FLAME_USTAR_LONGNAME_TYPE 'L' /* Identifies the NEXT file on the tape as having a long name. */


#pragma pack() //恢复默认

class FlameUstar
{
private:
int m_nFile;

public:
FlameUstar():m_nFile(-1){}
~FlameUstar(){DisConnect();}
public:
bool Connect(int nFile,long nBlockSize = 20 * 512,bool bArchive = false);
bool DisConnect();
bool ReadFileInfo(char* szptrArchiveFilename, struct stat * stptrStatus);
long InnerRead(char* szptrBuffer, long nBufferSize);
long ReadData(char* szptrBuffer, long nLength);
bool ReadFix(int64_t nFileSize);

public:
/*计算校验和*/
static uint32_t CalcChecksum(const FlameUstarHeader* stptrHeader);
/* 提取校验和字段 */
static uint32_t GetChecksum(const FlameUstarHeader* stptrHeader);

static bool VerifyHeader(const FlameUstarHeader* stptrHeader);

static long InnerRead(const char* buffer, char* szptrBuffer, long nBufferSize);
// Return true if conversion succeeded; false otherwise.

static bool Base256ToNum(uint64_t& val, const char* ptr, size_t len);

// Convert an octal number (possibly preceded by spaces) to numeric form.
// Stop either at the end of the field or at first '\0' (if any).

static bool OctalToNum(uint64_t& val, const char* ptr, size_t len);

static int64_t CalcSpaceSize(int64_t nSize);

// Return 0 (false) if conversion failed; 1 if the value was read into
// as a conventional octal string (perhaps, without the terminating '\0');
// or -1 if base-256 representation used.

static int DecodeUint8(uint64_t& val, const char* ptr, size_t len);

/*
* 提取长度字段。
*/
static int64_t GetSize(const FlameUstarHeader* stptrHeader);

/*
* 提取时间字段。
*/
static time_t GetMtime(const FlameUstarHeader* stptrHeader);

/*
* 提取权限字段。
*/
static uint32_t GetMode(const FlameUstarHeader* stptrHeader);

static bool ReadFileInfo(const char* buffer, char* szptrArchiveFilename, struct stat * stptrStatus);

};

#endif /* USTAR_H */


.cpp

flame_ustar.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/*
* File: ustar.cpp
*
*
* Created on 2021年4月9日, 上午9:57
*/

#include "flame_ustar.h"

#include <unistd.h>
#include <fcntl.h>


/**/
bool FlameUstar::Connect(int nFile, long nBlockSize /*= 20 * 512*/, bool bArchive /*= false*/)
{
bool bResult = false;

do
{
/*Must be close old*/
if (m_nFile>0)
break;
/*Check handle of file*/
if (nFile <= 0)
break;
/*Check block size*/
if (nBlockSize % 512 != 0 )
break;
/**/
m_nFile = nFile;

bResult = true;

}while(0);

return bResult;
}

bool FlameUstar::DisConnect()
{
bool bResult = false;
do
{
if (m_nFile <= 0)
break;
/**/
bResult = true;
}
while (0);

return bResult;
}


/*计算校验和*/
uint32_t FlameUstar::CalcChecksum(const FlameUstarHeader* stptrHeader)
{
uint32_t nChecksum = 0;

if (stptrHeader)
{
int i = 0;
for (; i < 148; ++i)
{
nChecksum += *(((unsigned char*) stptrHeader) + i);
}
//+8 for skip “checksum”
for (i += 8; i < 512; ++i) //...........
{
nChecksum += *(((unsigned char*) stptrHeader) + i);
}
nChecksum += 256;
}

return nChecksum;
}


/*
* 提取校验和字段。
*/
uint32_t FlameUstar::GetChecksum(const FlameUstarHeader* stptrHeader)
{
uint32_t nResult = 0;

if (stptrHeader)
{
char szBuffer[64] = {0};
memcpy(szBuffer, stptrHeader->chksum, sizeof (stptrHeader->chksum));
sscanf(szBuffer, "%o", &nResult);
}

return nResult;
}


bool FlameUstar::VerifyHeader(const FlameUstarHeader* stptrHeader)
{
bool bResult = false;

if (stptrHeader)
{
do
{
/**/
if (strncmp(stptrHeader->magic, TMAGIC, strlen(TMAGIC)) != 0)
break;

/*check sum*/
uint32_t nExpectChecksum = FlameUstar::GetChecksum(stptrHeader);
uint32_t nChecksum = FlameUstar::CalcChecksum(stptrHeader);
if (nExpectChecksum != nChecksum)
break;
/**/
bResult = true;

}
while (0);
}

return bResult;
}

long FlameUstar::InnerRead(const char* cptrDataBuffer, char* szptrBuffer, long nBufferSize)
{
long nResult = -1;
if (cptrDataBuffer)
{
memcpy(szptrBuffer, cptrDataBuffer, nBufferSize);
nResult = nBufferSize;
}
return nResult;
}
long FlameUstar::ReadData(char* szptrBuffer, long n_length)
{
return InnerRead(szptrBuffer, n_length);
}
bool FlameUstar::ReadFix(int64_t nFileSize)
{
bool bResult = false;

/**/
int64_t nModSize = nFileSize % FLAME_USTAR_TABLE_SIZE;
long n_fix_length = ((nModSize > 0) ? (FLAME_USTAR_TABLE_SIZE - nModSize) : (0));
/**/
if (!(bResult = (n_fix_length == 0)))
{
/**/
char sz_fix_data[FLAME_USTAR_TABLE_SIZE] = {0};
bResult = (InnerRead(sz_fix_data, n_fix_length) == n_fix_length);
}

return bResult;
}

long FlameUstar::InnerRead(char* szptrBuffer, long nBufferSize)
{
long nResult = -1;

if (m_nFile>0){
nResult = ::read(m_nFile, szptrBuffer, nBufferSize);
}
return nResult;
}

// Return true if conversion succeeded; false otherwise.

bool FlameUstar::Base256ToNum(uint64_t& val, const char* ptr, size_t len)
{
// const uint64_t lim = UINT64_MAX >> 8;
const uint64_t lim = 0xFFFFFFFFFFFFFFFFULL >> 8;
if (*ptr & '\x40')
{ // negative base-256?
return false;
}
val = *ptr++ & '\x3F';
while (--len)
{
if (val > lim)
{
return false;
}
val <<= 8;
val |= (unsigned char) (*ptr++);
}
return true;
}

// Convert an octal number (possibly preceded by spaces) to numeric form.
// Stop either at the end of the field or at first '\0' (if any).

bool FlameUstar::OctalToNum(uint64_t& val, const char* ptr, size_t len)
{
//_ASSERT(len > 0);
size_t i = *ptr ? 0 : 1;
while (i < len && ptr[i])
{
if (!isspace((unsigned char) ptr[i]))
break;
i++;
}
val = 0;
bool okay = false;
while (i < len && ptr[i] >= '0' && ptr[i] <= '7')
{
okay = true;
val <<= 3;
val |= ptr[i++] - '0';
}
while (i < len && ptr[i])
{
if (!isspace((unsigned char) ptr[i]))
return false;
i++;
}
return okay;
}

int64_t FlameUstar::CalcSpaceSize(int64_t nSize)
{
int64_t nResult = 0;

if (nSize > 0)
{
int64_t nModSize = nSize % FLAME_USTAR_TABLE_SIZE;
nResult = (nSize + ((nModSize > 0) ? (FLAME_USTAR_TABLE_SIZE - nModSize) : (0)));
}

return nResult;
}


// Return 0 (false) if conversion failed; 1 if the value was read into
// as a conventional octal string (perhaps, without the terminating '\0');
// or -1 if base-256 representation used.

int FlameUstar::DecodeUint8(uint64_t& val, const char* ptr, size_t len)
{
if (*ptr & '\x80')
{
return FlameUstar::Base256ToNum(val, ptr, len) ? -1/*okay*/ : 0/*failure*/;
}
else
{
return FlameUstar::OctalToNum(val, ptr, len) ? 1/*okay*/ : 0/*failure*/;
}
}

/*
* 提取长度字段。
*/
int64_t FlameUstar::GetSize(const FlameUstarHeader* stptrHeader)
{
uint64_t nResult = 0;

if (stptrHeader)
{
char szBuffer[64] = {0};
memcpy(szBuffer, stptrHeader->size, sizeof (stptrHeader->size));
FlameUstar::DecodeUint8(nResult, szBuffer, sizeof (stptrHeader->size));
}

return nResult;
}

/*
* 提取时间字段。
*/
time_t FlameUstar::GetMtime(const FlameUstarHeader* stptrHeader)
{
time_t nResult = 0;

if (stptrHeader)
{
char szBuffer[64] = {0};
memcpy(szBuffer, stptrHeader->mtime, sizeof (stptrHeader->mtime));
sscanf(szBuffer, "%o", &nResult);
}

return nResult;
}

/*
* 提取权限字段。
*/
uint32_t FlameUstar::GetMode(const FlameUstarHeader* stptrHeader)
{
uint32_t nResult = 0;

if (stptrHeader)
{
char szBuffer[64] = {0};
memcpy(szBuffer, stptrHeader->mode, sizeof (stptrHeader->mode));
sscanf(szBuffer, "%o", &nResult);
}

return nResult;
}

bool FlameUstar::ReadFileInfo(const char* cpDataBuffer, char* szpArchiveFilename, struct stat * stpstatus)
{
bool bResult = false;
if (szpArchiveFilename && stpstatus)
{
int nMove=0;
/**/
FlameUstarHeader objHeader{0};
char szlongname[PATH_MAX]{0};
char szlonglink[PATH_MAX]{0};

if (szlongname && szlonglink)
{
/*until find header or error*/
while (FlameUstar::InnerRead(cpDataBuffer+nMove, (char*) &objHeader, FLAME_USTAR_TABLE_SIZE) == FLAME_USTAR_TABLE_SIZE)
{
nMove+=FLAME_USTAR_TABLE_SIZE;
if (!FlameUstar::VerifyHeader(&objHeader))
break;

if (FLAME_USTAR_LONGNAME_TYPE == objHeader.typeflag)
{
if (strncmp(objHeader.name, FLAME_USTAR_LONGNAME_MAGIC, strlen(FLAME_USTAR_LONGNAME_MAGIC)) != 0)
break;
/*read long filename*/
int nNameLen = FlameUstar::GetSize(&objHeader);
if (nNameLen <= 0)
break;
int nNameSpaceSize = FlameUstar::CalcSpaceSize(nNameLen);
if (FlameUstar::InnerRead(cpDataBuffer+nMove, szlongname, nNameSpaceSize) != nNameSpaceSize)
break;
nMove+=nNameSpaceSize;
}
else if (FLAME_USTAR_LONGLINK_TYPE == objHeader.typeflag)
{
if (strncmp(objHeader.name, FLAME_USTAR_LONGNAME_MAGIC, strlen(FLAME_USTAR_LONGNAME_MAGIC)) != 0)
break;
/*read long linkname*/
int nNameLen = FlameUstar::GetSize(&objHeader);
if (nNameLen <= 0)
break;
int nNameSpaceSize = FlameUstar::CalcSpaceSize(nNameLen);
if (FlameUstar::InnerRead(cpDataBuffer+nMove, szlonglink, nNameSpaceSize) != nNameSpaceSize)
break;
nMove+=nNameSpaceSize;
}
else
{
/**/
if (REGTYPE == objHeader.typeflag || AREGTYPE == objHeader.typeflag)
stpstatus->st_mode = __S_IFREG;
else if (SYMTYPE == objHeader.typeflag)
stpstatus->st_mode = __S_IFLNK;
else if (DIRTYPE == objHeader.typeflag)
stpstatus->st_mode = __S_IFDIR;
else if (CHRTYPE == objHeader.typeflag)
stpstatus->st_mode = __S_IFCHR;
else if (BLKTYPE == objHeader.typeflag)
stpstatus->st_mode = __S_IFBLK;
else if (FIFOTYPE == objHeader.typeflag)
stpstatus->st_mode = __S_IFIFO;
else
break;
/*Analytic properties */
stpstatus->st_size = FlameUstar::GetSize(&objHeader);
stpstatus->st_mode |= FlameUstar::GetMode(&objHeader);
stpstatus->st_mtim.tv_sec = FlameUstar::GetMtime(&objHeader);
/*copy name*/
if (*szlongname != '\0')
strncpy(szpArchiveFilename, szlongname, PATH_MAX);
else
strncpy(szpArchiveFilename, objHeader.name, sizeof (objHeader.name));

/*set TRUE*/
bResult = true;
/*return */
break;
}

}
/**/
}

}
return bResult;
}


bool FlameUstar::ReadFileInfo(char* szptrArchiveFilename, struct stat * stptrStatus)
{
bool bResult = false;
if (szptrArchiveFilename && stptrStatus)
{
int nMove=0;
/**/
FlameUstarHeader objHeader{0};
char szLongname[PATH_MAX]{0};
char szLonglink[PATH_MAX]{0};

if (szLongname && szLonglink)
{
/*until find header or error*/
while (InnerRead((char*) &objHeader, FLAME_USTAR_TABLE_SIZE) == FLAME_USTAR_TABLE_SIZE)
{
nMove+=FLAME_USTAR_TABLE_SIZE;
if (!FlameUstar::VerifyHeader(&objHeader))
break;

if (FLAME_USTAR_LONGNAME_TYPE == objHeader.typeflag)
{
if (strncmp(objHeader.name, FLAME_USTAR_LONGNAME_MAGIC, strlen(FLAME_USTAR_LONGNAME_MAGIC)) != 0)
break;
/*read long filename*/
int nNameLen = FlameUstar::GetSize(&objHeader);
if (nNameLen <= 0)
break;
int nNameSpaceSize = FlameUstar::CalcSpaceSize(nNameLen);
if (InnerRead(szLongname, nNameSpaceSize) != nNameSpaceSize)
break;
nMove+=nNameSpaceSize;
}
else if (FLAME_USTAR_LONGLINK_TYPE == objHeader.typeflag)
{
if (strncmp(objHeader.name, FLAME_USTAR_LONGNAME_MAGIC, strlen(FLAME_USTAR_LONGNAME_MAGIC)) != 0)
break;
/*read long linkname*/
int nNameLen = FlameUstar::GetSize(&objHeader);
if (nNameLen <= 0)
break;
int nNameSpaceSize = FlameUstar::CalcSpaceSize(nNameLen);
if (InnerRead(szLonglink, nNameSpaceSize) != nNameSpaceSize)
break;
nMove+=nNameSpaceSize;
}
else
{
/**/
if (REGTYPE == objHeader.typeflag || AREGTYPE == objHeader.typeflag)
stptrStatus->st_mode = __S_IFREG;
else if (SYMTYPE == objHeader.typeflag)
stptrStatus->st_mode = __S_IFLNK;
else if (DIRTYPE == objHeader.typeflag)
stptrStatus->st_mode = __S_IFDIR;
else if (CHRTYPE == objHeader.typeflag)
stptrStatus->st_mode = __S_IFCHR;
else if (BLKTYPE == objHeader.typeflag)
stptrStatus->st_mode = __S_IFBLK;
else if (FIFOTYPE == objHeader.typeflag)
stptrStatus->st_mode = __S_IFIFO;
else
break;
/*Analytic properties */
stptrStatus->st_size = FlameUstar::GetSize(&objHeader);
stptrStatus->st_mode |= FlameUstar::GetMode(&objHeader);
stptrStatus->st_mtim.tv_sec = FlameUstar::GetMtime(&objHeader);
/*copy name*/
if (*szLongname != '\0')
strncpy(szptrArchiveFilename, szLongname, PATH_MAX);
else
strncpy(szptrArchiveFilename, objHeader.name, sizeof (objHeader.name));

/*set TRUE*/
bResult = true;
/*return */
break;
}

}
/**/
}

}
return bResult;
}


demo

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

/*
* File: main.cpp
*
*
* Created on 2021年4月8日, 下午12:52
*/

#include <cstdlib>
#include <list>
#include <tar.h>
#include<sys/stat.h>
#include <getopt.h>
#include <fcntl.h>


#include "flame_ustar.h"

using namespace std;

int CheckTar(const char * szFullName)
{
int nResult=0;
bool bResult = false;
char szArchiveFilename[4096];
struct stat stStatus;

const int TAPE_BUF_MAX = 512*512;
char* dataBuffer = new char[TAPE_BUF_MAX];
do{
int fd = open(szFullName, O_RDONLY);
if (0 > fd)
break;
FlameUstar ustar;
bResult = ustar.Connect(fd);
if (!bResult)
break;
bResult = ustar.ReadFileInfo(szArchiveFilename, &stStatus);
if (!bResult)
break;
// 大小
uint64_t needReadSize = stStatus.st_size;

while(needReadSize>0)
{
while(needReadSize > 0)
{// data
memset(dataBuffer, 0, TAPE_BUF_MAX);
if (needReadSize > TAPE_BUF_MAX)
{
long rd = ustar.ReadData(dataBuffer, TAPE_BUF_MAX);
if (rd != TAPE_BUF_MAX)
{
nResult = -1;
break;
}
needReadSize -= rd;
}
else
{
long rd = ustar.ReadData(dataBuffer, needReadSize);
if (rd != needReadSize)
{
nResult = -1;
break;
}
needReadSize -= rd;
if (!ustar.ReadFix(stStatus.st_size))
{
nResult = -1;
break;
}
}
}
}
}while(0);

delete [] dataBuffer;
return 0;
}

/*
*
*/
int main(int argc, char** argv) {
const char * cszPath = "/opt/tmp/1.tar";
CheckTar(cszPath);
return 0;
}