xref: /haiku/src/apps/haikudepot/tar/TarArchiveHeader.cpp (revision 25f1ddecf7c81f9fd03fbd9463aa6566b8d01fc4)
1 /*
2  * Copyright 2017-2020, Andrew Lindesay <apl@lindesay.co.nz>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include "TarArchiveHeader.h"
7 
8 #include "Logger.h"
9 
10 #define OFFSET_FILENAME 0
11 #define OFFSET_LENGTH 124
12 #define OFFSET_CHECKSUM 148
13 #define OFFSET_FILETYPE 156
14 
15 #define LENGTH_FILENAME 100
16 #define LENGTH_LENGTH 12
17 #define LENGTH_CHECKSUM 8
18 #define LENGTH_BLOCK 512
19 
20 
21 TarArchiveHeader::TarArchiveHeader(const BString& fileName, uint64 length,
22 		tar_file_type fileType)
23 		:
24 		fFileName(fileName),
25 		fLength(length),
26 		fFileType(fileType)
27 {
28 }
29 
30 tar_file_type
31 TarArchiveHeader::_ReadFileType(unsigned char data) {
32 	switch (data) {
33 		case 0:
34 		case '0':
35 			return TAR_FILE_TYPE_NORMAL;
36 
37 		default:
38 			return TAR_FILE_TYPE_OTHER;
39 	}
40 }
41 
42 
43 const BString
44 TarArchiveHeader::_ReadString(const unsigned char *data, size_t dataLength)
45 {
46 	uint32 actualLength = 0;
47 
48 	while (actualLength < dataLength && 0 != data[actualLength])
49 		actualLength++;
50 
51 	return BString((const char *) data, actualLength);
52 }
53 
54 /*
55  * This is an octal value represented as an ASCII string.
56  */
57 
58 static bool tar_is_octal_digit(unsigned char c)
59 {
60 	switch (c) {
61 		case '0':
62 		case '1':
63 		case '2':
64 		case '3':
65 		case '4':
66 		case '5':
67 		case '6':
68 		case '7':
69 			return true;
70 
71 		default:
72 			return false;
73 	}
74 }
75 
76 uint32
77 TarArchiveHeader::_ReadNumeric(const unsigned char *data, size_t dataLength)
78 {
79 	uint32 actualLength = 0;
80 
81 	while (actualLength < dataLength && tar_is_octal_digit(data[actualLength]))
82 		actualLength++;
83 
84 	uint32 factor = 1;
85 	uint32 result = 0;
86 
87 	for (uint32 i = 0; i < actualLength; i++) {
88 		result += (data[actualLength - (1 + i)] - '0') * factor;
89 		factor *= 8;
90 	}
91 
92 	return result;
93 }
94 
95 uint32
96 TarArchiveHeader::_CalculateChecksum(const unsigned char* block)
97 {
98 	uint32 result = 0;
99 
100 	for (uint32 i = 0; i < LENGTH_BLOCK; i++) {
101 		if (i >= OFFSET_CHECKSUM && i < OFFSET_CHECKSUM + LENGTH_CHECKSUM)
102 			result += 32;
103 		else
104 			result += block[i];
105 	}
106 
107 	return result;
108 }
109 
110 TarArchiveHeader*
111 TarArchiveHeader::CreateFromBlock(const unsigned char* block)
112 {
113 	uint32 actualChecksum = _CalculateChecksum(block);
114 	uint32 expectedChecksum = _ReadNumeric(&block[OFFSET_CHECKSUM],
115 		LENGTH_CHECKSUM);
116 
117 	if(actualChecksum != expectedChecksum) {
118 		HDERROR("tar archive header has bad checksum;"
119 			"expected %" B_PRIu32 " actual %" B_PRIu32,
120 			expectedChecksum, actualChecksum)
121 	} else {
122 		return new TarArchiveHeader(
123 			_ReadString(&block[OFFSET_FILENAME], LENGTH_FILENAME),
124 			_ReadNumeric(&block[OFFSET_LENGTH], LENGTH_LENGTH),
125 			_ReadFileType(block[OFFSET_FILETYPE]));
126 	}
127 
128 	return NULL;
129 }
130 
131 const BString&
132 TarArchiveHeader::GetFileName() const
133 {
134 	return fFileName;
135 }
136 
137 size_t
138 TarArchiveHeader::GetLength() const
139 {
140 	return fLength;
141 }
142 
143 
144 tar_file_type
145 TarArchiveHeader::GetFileType() const
146 {
147 	return fFileType;
148 }
149