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