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