ext_header.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. Copyright (c) 2011, 2012, Simon Howard
  3. Permission to use, copy, modify, and/or distribute this software
  4. for any purpose with or without fee is hereby granted, provided
  5. that the above copyright notice and this permission notice appear
  6. in all copies.
  7. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  8. WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  9. WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  10. AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
  11. CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "ext_header.h"
  19. #include "lha_endian.h"
  20. //
  21. // Extended header parsing.
  22. //
  23. // Extended headers were introduced with LHA v2 - various different
  24. // tools support different extended headers. Some are operating system
  25. // specific.
  26. //
  27. // Extended header types:
  28. #define LHA_EXT_HEADER_COMMON 0x00
  29. #define LHA_EXT_HEADER_FILENAME 0x01
  30. #define LHA_EXT_HEADER_PATH 0x02
  31. #define LHA_EXT_HEADER_MULTI_DISC 0x39
  32. #define LHA_EXT_HEADER_COMMENT 0x3f
  33. #define LHA_EXT_HEADER_WINDOWS_TIMESTAMPS 0x41
  34. #define LHA_EXT_HEADER_UNIX_PERMISSION 0x50
  35. #define LHA_EXT_HEADER_UNIX_UID_GID 0x51
  36. #define LHA_EXT_HEADER_UNIX_GROUP 0x52
  37. #define LHA_EXT_HEADER_UNIX_USER 0x53
  38. #define LHA_EXT_HEADER_UNIX_TIMESTAMP 0x54
  39. #define LHA_EXT_HEADER_OS9 0xcc
  40. /**
  41. * Structure representing an extended header type.
  42. */
  43. typedef struct {
  44. /**
  45. * Header number.
  46. *
  47. * Each extended header type has a unique byte value that represents
  48. * it.
  49. */
  50. uint8_t num;
  51. /**
  52. * Callback function for parsing an extended header block.
  53. *
  54. * @param header The file header structure in which to store
  55. * decoded data.
  56. * @param data Pointer to the header data to decode.
  57. * @param data_len Size of the header data, in bytes.
  58. * @return Non-zero if successful, or zero for failure.
  59. */
  60. int (*decoder)(LHAFileHeader *header, uint8_t *data, size_t data_len);
  61. /** Minimum length for a header of this type. */
  62. size_t min_len;
  63. } LHAExtHeaderType;
  64. // Common header (0x00).
  65. //
  66. // This contains a 16-bit CRC of the entire LHA header.
  67. static int ext_header_common_decoder(LHAFileHeader *header,
  68. uint8_t *data,
  69. size_t data_len)
  70. {
  71. header->extra_flags |= LHA_FILE_COMMON_CRC;
  72. header->common_crc = lha_decode_uint16(data);
  73. // There is a catch-22 in calculating the CRC, because the field
  74. // containing the CRC is part of the data being CRC'd. The solution
  75. // is that the CRC is calculated with the CRC field set to zero.
  76. // Therefore, now that the CRC has been read, set the field to
  77. // zero in the raw_data array so that the CRC can be calculated
  78. // correctly.
  79. data[0] = 0x00;
  80. data[1] = 0x00;
  81. // TODO: Some platforms (OS/2, Unix) put extra data in the common
  82. // header which might also be decoded.
  83. return 1;
  84. }
  85. static LHAExtHeaderType lha_ext_header_common = {
  86. LHA_EXT_HEADER_COMMON,
  87. ext_header_common_decoder,
  88. 2
  89. };
  90. // Filename header (0x01).
  91. //
  92. // This stores the filename for the file. This is essential on level 2/3
  93. // headers, as the filename field is no longer part of the standard
  94. // header.
  95. static int ext_header_filename_decoder(LHAFileHeader *header,
  96. uint8_t *data,
  97. size_t data_len)
  98. {
  99. char *new_filename;
  100. unsigned int i;
  101. new_filename = malloc(data_len + 1);
  102. if (new_filename == NULL) {
  103. return 0;
  104. }
  105. memcpy(new_filename, data, data_len);
  106. new_filename[data_len] = '\0';
  107. // Sanitize the filename that was read. It is not allowed to
  108. // contain a path separator, which could potentially be used
  109. // to do something malicious.
  110. for (i = 0; new_filename[i] != '\0'; ++i) {
  111. if (new_filename[i] == '/') {
  112. new_filename[i] = '_';
  113. }
  114. }
  115. free(header->filename);
  116. header->filename = new_filename;
  117. return 1;
  118. }
  119. static LHAExtHeaderType lha_ext_header_filename = {
  120. LHA_EXT_HEADER_FILENAME,
  121. ext_header_filename_decoder,
  122. 1
  123. };
  124. // Path header (0x02).
  125. //
  126. // This stores the directory path of the file. A value of 0xff is used
  127. // as the path separator. It is supposed to include a terminating path
  128. // separator as the last character.
  129. static int ext_header_path_decoder(LHAFileHeader *header,
  130. uint8_t *data,
  131. size_t data_len)
  132. {
  133. unsigned int i;
  134. uint8_t *new_path;
  135. new_path = malloc(data_len + 2);
  136. if (new_path == NULL) {
  137. return 0;
  138. }
  139. memcpy(new_path, data, data_len);
  140. new_path[data_len] = '\0';
  141. // Amiga LHA v1.22 generates path headers without a path
  142. // separator at the end of the string. This is broken (and
  143. // was fixed in a later version), but handle it correctly.
  144. if (new_path[data_len - 1] != 0xff) {
  145. new_path[data_len] = 0xff;
  146. new_path[data_len + 1] = '\0';
  147. ++data_len;
  148. }
  149. free(header->path);
  150. header->path = (char *) new_path;
  151. for (i = 0; i < data_len; ++i) {
  152. if (new_path[i] == 0xff) {
  153. new_path[i] = '/';
  154. }
  155. }
  156. return 1;
  157. }
  158. static LHAExtHeaderType lha_ext_header_path = {
  159. LHA_EXT_HEADER_PATH,
  160. ext_header_path_decoder,
  161. 1
  162. };
  163. // Windows timestamp header (0x41).
  164. //
  165. // This is a Windows-specific header that stores 64-bit timestamps in
  166. // Windows FILETIME format. The timestamps have 100ns accuracy, which is
  167. // much more accurate than the normal Unix time_t format.
  168. static int ext_header_windows_timestamps(LHAFileHeader *header,
  169. uint8_t *data,
  170. size_t data_len)
  171. {
  172. header->extra_flags |= LHA_FILE_WINDOWS_TIMESTAMPS;
  173. header->win_creation_time = lha_decode_uint64(data);
  174. header->win_modification_time = lha_decode_uint64(data + 8);
  175. header->win_access_time = lha_decode_uint64(data + 16);
  176. return 1;
  177. }
  178. static LHAExtHeaderType lha_ext_header_windows_timestamps = {
  179. LHA_EXT_HEADER_WINDOWS_TIMESTAMPS,
  180. ext_header_windows_timestamps,
  181. 24
  182. };
  183. // Unix permissions header (0x50).
  184. static int ext_header_unix_perms_decoder(LHAFileHeader *header,
  185. uint8_t *data,
  186. size_t data_len)
  187. {
  188. header->extra_flags |= LHA_FILE_UNIX_PERMS;
  189. header->unix_perms = lha_decode_uint16(data);
  190. return 1;
  191. }
  192. static LHAExtHeaderType lha_ext_header_unix_perms = {
  193. LHA_EXT_HEADER_UNIX_PERMISSION,
  194. ext_header_unix_perms_decoder,
  195. 2
  196. };
  197. // Unix UID/GID header (0x51).
  198. static int ext_header_unix_uid_gid_decoder(LHAFileHeader *header,
  199. uint8_t *data,
  200. size_t data_len)
  201. {
  202. header->extra_flags |= LHA_FILE_UNIX_UID_GID;
  203. header->unix_gid = lha_decode_uint16(data);
  204. header->unix_uid = lha_decode_uint16(data + 2);
  205. return 1;
  206. }
  207. static LHAExtHeaderType lha_ext_header_unix_uid_gid = {
  208. LHA_EXT_HEADER_UNIX_UID_GID,
  209. ext_header_unix_uid_gid_decoder,
  210. 4
  211. };
  212. // Unix username header (0x53).
  213. //
  214. // This stores a string containing the username. There don't seem to be
  215. // any tools that actually generate archives containing this header.
  216. static int ext_header_unix_username_decoder(LHAFileHeader *header,
  217. uint8_t *data,
  218. size_t data_len)
  219. {
  220. char *username;
  221. username = malloc(data_len + 1);
  222. if (username == NULL) {
  223. return 0;
  224. }
  225. memcpy(username, data, data_len);
  226. username[data_len] = '\0';
  227. free(header->unix_username);
  228. header->unix_username = username;
  229. return 1;
  230. }
  231. static LHAExtHeaderType lha_ext_header_unix_username = {
  232. LHA_EXT_HEADER_UNIX_USER,
  233. ext_header_unix_username_decoder,
  234. 1
  235. };
  236. // Unix group header (0x52).
  237. //
  238. // This stores a string containing the Unix group name. As with the
  239. // username header, there don't seem to be any tools that actually
  240. // generate archives containing this header.
  241. static int ext_header_unix_group_decoder(LHAFileHeader *header,
  242. uint8_t *data,
  243. size_t data_len)
  244. {
  245. char *group;
  246. group = malloc(data_len + 1);
  247. if (group == NULL) {
  248. return 0;
  249. }
  250. memcpy(group, data, data_len);
  251. group[data_len] = '\0';
  252. free(header->unix_group);
  253. header->unix_group = group;
  254. return 1;
  255. }
  256. static LHAExtHeaderType lha_ext_header_unix_group = {
  257. LHA_EXT_HEADER_UNIX_GROUP,
  258. ext_header_unix_group_decoder,
  259. 1
  260. };
  261. // Unix timestamp header (0x54).
  262. //
  263. // This stores a 32-bit Unix time_t timestamp representing the
  264. // modification time of the file.
  265. static int ext_header_unix_timestamp_decoder(LHAFileHeader *header,
  266. uint8_t *data,
  267. size_t data_len)
  268. {
  269. header->timestamp = lha_decode_uint32(data);
  270. return 1;
  271. }
  272. static LHAExtHeaderType lha_ext_header_unix_timestamp = {
  273. LHA_EXT_HEADER_UNIX_TIMESTAMP,
  274. ext_header_unix_timestamp_decoder,
  275. 4
  276. };
  277. // OS-9 (6809) header (0xcc)
  278. //
  279. // This stores OS-9 filesystem metadata.
  280. static int ext_header_os9_decoder(LHAFileHeader *header,
  281. uint8_t *data,
  282. size_t data_len)
  283. {
  284. // TODO: The OS-9 extended header contains various data, but
  285. // it's not clear what it's all for. Just extract the
  286. // permissions for now.
  287. header->os9_perms = lha_decode_uint16(data + 7);
  288. header->extra_flags |= LHA_FILE_OS9_PERMS;
  289. return 1;
  290. }
  291. static LHAExtHeaderType lha_ext_header_os9 = {
  292. LHA_EXT_HEADER_OS9,
  293. ext_header_os9_decoder,
  294. 12
  295. };
  296. // Table of extended headers.
  297. static const LHAExtHeaderType *ext_header_types[] = {
  298. &lha_ext_header_common,
  299. &lha_ext_header_filename,
  300. &lha_ext_header_path,
  301. &lha_ext_header_unix_perms,
  302. &lha_ext_header_unix_uid_gid,
  303. &lha_ext_header_unix_username,
  304. &lha_ext_header_unix_group,
  305. &lha_ext_header_unix_timestamp,
  306. &lha_ext_header_windows_timestamps,
  307. &lha_ext_header_os9,
  308. };
  309. #define NUM_HEADER_TYPES (sizeof(ext_header_types) / sizeof(*ext_header_types))
  310. /**
  311. * Look up the extended header parser for the specified header code.
  312. *
  313. * @param num Extended header type.
  314. * @return Matching @ref LHAExtHeaderType structure, or NULL if
  315. * not found for this header type.
  316. */
  317. static const LHAExtHeaderType *ext_header_for_num(uint8_t num)
  318. {
  319. unsigned int i;
  320. for (i = 0; i < NUM_HEADER_TYPES; ++i) {
  321. if (ext_header_types[i]->num == num) {
  322. return ext_header_types[i];
  323. }
  324. }
  325. return NULL;
  326. }
  327. int lha_ext_header_decode(LHAFileHeader *header,
  328. uint8_t num,
  329. uint8_t *data,
  330. size_t data_len)
  331. {
  332. const LHAExtHeaderType *htype;
  333. htype = ext_header_for_num(num);
  334. if (htype == NULL) {
  335. return 0;
  336. }
  337. if (data_len < htype->min_len) {
  338. return 0;
  339. }
  340. return htype->decoder(header, data, data_len);
  341. }