You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1133 lines
28 KiB

  1. /*
  2. * Attachment functions
  3. *
  4. * Copyright (C) 2008-2019, Joachim Metz <joachim.metz@gmail.com>
  5. *
  6. * Refer to AUTHORS for acknowledgements.
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. #include <common.h>
  22. #include <byte_stream.h>
  23. #include <memory.h>
  24. #include <types.h>
  25. #include "libpff_attached_file_io_handle.h"
  26. #include "libpff_attachment.h"
  27. #include "libpff_debug.h"
  28. #include "libpff_definitions.h"
  29. #include "libpff_item.h"
  30. #include "libpff_item_descriptor.h"
  31. #include "libpff_item_tree.h"
  32. #include "libpff_libcdata.h"
  33. #include "libpff_libcerror.h"
  34. #include "libpff_libcnotify.h"
  35. #include "libpff_libfcache.h"
  36. #include "libpff_libfdata.h"
  37. #include "libpff_libfmapi.h"
  38. #include "libpff_local_descriptor_value.h"
  39. #include "libpff_local_descriptors_tree.h"
  40. #include "libpff_mapi.h"
  41. #include "libpff_record_entry.h"
  42. #include "libpff_record_set.h"
  43. #include "libpff_types.h"
  44. /* Retrieves the attachment type
  45. * Returns 1 if successful or -1 on error
  46. */
  47. int libpff_attachment_get_type(
  48. libpff_item_t *attachment,
  49. int *attachment_type,
  50. libcerror_error_t **error )
  51. {
  52. libpff_internal_item_t *internal_item = NULL;
  53. libpff_record_entry_t *record_entry = NULL;
  54. libpff_record_set_t *record_set = NULL;
  55. static char *function = "libpff_attachment_get_type";
  56. uint32_t attachment_method = 0;
  57. uint32_t value_type = 0;
  58. if( attachment == NULL )
  59. {
  60. libcerror_error_set(
  61. error,
  62. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  63. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  64. "%s: invalid attachment.",
  65. function );
  66. return( -1 );
  67. }
  68. internal_item = (libpff_internal_item_t *) attachment;
  69. if( internal_item->internal_file == NULL )
  70. {
  71. libcerror_error_set(
  72. error,
  73. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  74. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  75. "%s: invalid item - missing internal file.",
  76. function );
  77. return( -1 );
  78. }
  79. if( attachment_type == NULL )
  80. {
  81. libcerror_error_set(
  82. error,
  83. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  84. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  85. "%s: invalid attachment type.",
  86. function );
  87. return( -1 );
  88. }
  89. if( libpff_internal_item_get_entry_value_32bit_integer(
  90. internal_item,
  91. LIBPFF_ENTRY_TYPE_ATTACHMENT_METHOD,
  92. &attachment_method,
  93. error ) != 1 )
  94. {
  95. libcerror_error_set(
  96. error,
  97. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  98. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  99. "%s: unable to retrieve attachment method.",
  100. function );
  101. goto on_error;
  102. }
  103. if( ( attachment_method != LIBPFF_ATTACHMENT_METHOD_BY_VALUE )
  104. && ( attachment_method != LIBPFF_ATTACHMENT_METHOD_BY_REFERENCE )
  105. && ( attachment_method != LIBPFF_ATTACHMENT_METHOD_EMBEDDED_MESSAGE )
  106. && ( attachment_method != LIBPFF_ATTACHMENT_METHOD_OLE ) )
  107. {
  108. libcerror_error_set(
  109. error,
  110. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  111. LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
  112. "%s: unsupported attachment method: 0x%08" PRIx32 ".",
  113. function,
  114. attachment_method );
  115. goto on_error;
  116. }
  117. if( attachment_method == LIBPFF_ATTACHMENT_METHOD_BY_REFERENCE )
  118. {
  119. *attachment_type = LIBPFF_ATTACHMENT_TYPE_REFERENCE;
  120. }
  121. else if( ( attachment_method == LIBPFF_ATTACHMENT_METHOD_BY_VALUE )
  122. || ( attachment_method == LIBPFF_ATTACHMENT_METHOD_EMBEDDED_MESSAGE )
  123. || ( attachment_method == LIBPFF_ATTACHMENT_METHOD_OLE ) )
  124. {
  125. if( libpff_item_get_record_set_by_index(
  126. attachment,
  127. 0,
  128. &record_set,
  129. error ) != 1 )
  130. {
  131. libcerror_error_set(
  132. error,
  133. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  134. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  135. "%s: unable to retrieve record set: 0.",
  136. function );
  137. goto on_error;
  138. }
  139. if( libpff_record_set_get_entry_by_type(
  140. record_set,
  141. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT,
  142. 0,
  143. &record_entry,
  144. LIBPFF_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE,
  145. error ) != 1 )
  146. {
  147. libcerror_error_set(
  148. error,
  149. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  150. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  151. "%s: unable to retrieve record entry: 0x%04 " PRIx32 ".",
  152. function,
  153. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT );
  154. goto on_error;
  155. }
  156. if( libpff_record_entry_get_value_type(
  157. record_entry,
  158. &value_type,
  159. error ) != 1 )
  160. {
  161. libcerror_error_set(
  162. error,
  163. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  164. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  165. "%s: unable to retrieve value type.",
  166. function );
  167. goto on_error;
  168. }
  169. if( value_type == LIBPFF_VALUE_TYPE_BINARY_DATA )
  170. {
  171. *attachment_type = LIBPFF_ATTACHMENT_TYPE_DATA;
  172. }
  173. else if( value_type == LIBPFF_VALUE_TYPE_OBJECT )
  174. {
  175. if( attachment_method == LIBPFF_ATTACHMENT_METHOD_EMBEDDED_MESSAGE )
  176. {
  177. *attachment_type = LIBPFF_ATTACHMENT_TYPE_ITEM;
  178. }
  179. else if( attachment_method == LIBPFF_ATTACHMENT_METHOD_OLE )
  180. {
  181. *attachment_type = LIBPFF_ATTACHMENT_TYPE_DATA;
  182. }
  183. else
  184. {
  185. libcerror_error_set(
  186. error,
  187. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  188. LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
  189. "%s: unsupported attachment method: 0x%08" PRIx32 " for object value type.",
  190. function,
  191. attachment_method );
  192. goto on_error;
  193. }
  194. }
  195. else
  196. {
  197. libcerror_error_set(
  198. error,
  199. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  200. LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
  201. "%s: unsupported entry value type: 0x%08" PRIx32 ".",
  202. function,
  203. value_type );
  204. goto on_error;
  205. }
  206. if( libpff_record_entry_free(
  207. &record_entry,
  208. error ) != 1 )
  209. {
  210. libcerror_error_set(
  211. error,
  212. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  213. LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
  214. "%s: unable to free record entry.",
  215. function );
  216. goto on_error;
  217. }
  218. if( libpff_record_set_free(
  219. &record_set,
  220. error ) != 1 )
  221. {
  222. libcerror_error_set(
  223. error,
  224. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  225. LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
  226. "%s: unable to free record set.",
  227. function );
  228. goto on_error;
  229. }
  230. }
  231. return( 1 );
  232. on_error:
  233. if( record_entry != NULL )
  234. {
  235. libpff_record_entry_free(
  236. &record_entry,
  237. NULL );
  238. }
  239. if( record_set != NULL )
  240. {
  241. libpff_record_set_free(
  242. &record_set,
  243. NULL );
  244. }
  245. return( -1 );
  246. }
  247. /* Retrieves the attachment data size
  248. * Returns 1 if successful, 0 if not available or -1 on error
  249. */
  250. int libpff_attachment_get_data_size(
  251. libpff_item_t *attachment,
  252. size64_t *size,
  253. libcerror_error_t **error )
  254. {
  255. libpff_internal_item_t *internal_item = NULL;
  256. libpff_record_entry_t *record_entry = NULL;
  257. static char *function = "libpff_attachment_get_data_size";
  258. size_t value_data_size = 0;
  259. uint32_t value_type = 0;
  260. int result = 0;
  261. if( attachment == NULL )
  262. {
  263. libcerror_error_set(
  264. error,
  265. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  266. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  267. "%s: invalid attachment.",
  268. function );
  269. return( -1 );
  270. }
  271. internal_item = (libpff_internal_item_t *) attachment;
  272. if( internal_item->internal_file == NULL )
  273. {
  274. libcerror_error_set(
  275. error,
  276. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  277. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  278. "%s: invalid attachment - missing internal file.",
  279. function );
  280. return( -1 );
  281. }
  282. result = libpff_item_values_get_record_entry_by_type(
  283. internal_item->item_values,
  284. internal_item->internal_file->name_to_id_map_list,
  285. internal_item->internal_file->io_handle,
  286. internal_item->file_io_handle,
  287. internal_item->internal_file->offsets_index,
  288. 0,
  289. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT,
  290. 0,
  291. &record_entry,
  292. LIBPFF_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE,
  293. error );
  294. if( result == -1 )
  295. {
  296. libcerror_error_set(
  297. error,
  298. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  299. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  300. "%s: unable to retrieve record entry.",
  301. function );
  302. return( -1 );
  303. }
  304. else if( result != 0 )
  305. {
  306. if( libpff_record_entry_get_value_type(
  307. record_entry,
  308. &value_type,
  309. error ) != 1 )
  310. {
  311. libcerror_error_set(
  312. error,
  313. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  314. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  315. "%s: unable to retrieve value type.",
  316. function );
  317. return( -1 );
  318. }
  319. /* The OLE attachment method could refer to an OLE embedded object
  320. */
  321. if( value_type == LIBPFF_VALUE_TYPE_OBJECT )
  322. {
  323. if( internal_item->embedded_object_data_stream == NULL )
  324. {
  325. if( libpff_internal_item_get_embedded_object_data(
  326. internal_item,
  327. record_entry,
  328. error ) == -1 )
  329. {
  330. libcerror_error_set(
  331. error,
  332. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  333. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  334. "%s: unable to retrieve embedded object data.",
  335. function );
  336. return( -1 );
  337. }
  338. }
  339. if( libfdata_stream_get_size(
  340. internal_item->embedded_object_data_stream,
  341. size,
  342. error ) != 1 )
  343. {
  344. libcerror_error_set(
  345. error,
  346. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  347. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  348. "%s: unable to retrieve value data stream size.",
  349. function );
  350. return( -1 );
  351. }
  352. }
  353. else
  354. {
  355. if( size == NULL )
  356. {
  357. libcerror_error_set(
  358. error,
  359. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  360. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  361. "%s: invalid size.",
  362. function );
  363. return( -1 );
  364. }
  365. if( libpff_record_entry_get_data_size(
  366. record_entry,
  367. &value_data_size,
  368. error ) != 1 )
  369. {
  370. libcerror_error_set(
  371. error,
  372. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  373. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  374. "%s: unable to retrieve value data size.",
  375. function );
  376. return( -1 );
  377. }
  378. *size = (size64_t) value_data_size;
  379. }
  380. }
  381. return( result );
  382. }
  383. /* Reads attachment data from the current offset into a buffer
  384. * Returns the number of bytes read or -1 on error
  385. */
  386. ssize_t libpff_attachment_data_read_buffer(
  387. libpff_item_t *attachment,
  388. uint8_t *buffer,
  389. size_t buffer_size,
  390. libcerror_error_t **error )
  391. {
  392. libpff_internal_item_t *internal_item = NULL;
  393. libpff_record_entry_t *record_entry = NULL;
  394. static char *function = "libpff_attachment_data_read_buffer";
  395. ssize_t read_count = 0;
  396. uint32_t value_type = 0;
  397. int result = 0;
  398. if( attachment == NULL )
  399. {
  400. libcerror_error_set(
  401. error,
  402. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  403. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  404. "%s: invalid attachment.",
  405. function );
  406. return( -1 );
  407. }
  408. internal_item = (libpff_internal_item_t *) attachment;
  409. if( internal_item->internal_file == NULL )
  410. {
  411. libcerror_error_set(
  412. error,
  413. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  414. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  415. "%s: invalid attachment - missing internal file.",
  416. function );
  417. return( -1 );
  418. }
  419. result = libpff_item_values_get_record_entry_by_type(
  420. internal_item->item_values,
  421. internal_item->internal_file->name_to_id_map_list,
  422. internal_item->internal_file->io_handle,
  423. internal_item->file_io_handle,
  424. internal_item->internal_file->offsets_index,
  425. 0,
  426. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT,
  427. 0,
  428. &record_entry,
  429. LIBPFF_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE,
  430. error );
  431. if( result != 1 )
  432. {
  433. libcerror_error_set(
  434. error,
  435. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  436. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  437. "%s: unable to retrieve record entry.",
  438. function );
  439. return( -1 );
  440. }
  441. if( libpff_record_entry_get_value_type(
  442. record_entry,
  443. &value_type,
  444. error ) != 1 )
  445. {
  446. libcerror_error_set(
  447. error,
  448. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  449. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  450. "%s: unable to retrieve value type.",
  451. function );
  452. return( -1 );
  453. }
  454. /* The OLE attachment method could refer to an OLE embedded object
  455. */
  456. if( value_type == LIBPFF_VALUE_TYPE_OBJECT )
  457. {
  458. if( internal_item->embedded_object_data_stream == NULL )
  459. {
  460. if( libpff_internal_item_get_embedded_object_data(
  461. internal_item,
  462. record_entry,
  463. error ) == -1 )
  464. {
  465. libcerror_error_set(
  466. error,
  467. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  468. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  469. "%s: unable to retrieve embedded object data.",
  470. function );
  471. return( -1 );
  472. }
  473. }
  474. read_count = libfdata_stream_read_buffer(
  475. internal_item->embedded_object_data_stream,
  476. (intptr_t *) internal_item->file_io_handle,
  477. buffer,
  478. buffer_size,
  479. 0,
  480. error );
  481. if( read_count == -1 )
  482. {
  483. libcerror_error_set(
  484. error,
  485. LIBCERROR_ERROR_DOMAIN_IO,
  486. LIBCERROR_IO_ERROR_READ_FAILED,
  487. "%s: unable to read buffer from embedded object data stream.",
  488. function );
  489. return( -1 );
  490. }
  491. }
  492. else
  493. {
  494. read_count = libpff_record_entry_read_buffer(
  495. record_entry,
  496. buffer,
  497. buffer_size,
  498. error );
  499. if( read_count == -1 )
  500. {
  501. libcerror_error_set(
  502. error,
  503. LIBCERROR_ERROR_DOMAIN_IO,
  504. LIBCERROR_IO_ERROR_READ_FAILED,
  505. "%s: unable to read buffer from record entry.",
  506. function );
  507. return( -1 );
  508. }
  509. }
  510. return( read_count );
  511. }
  512. /* Seeks a certain offset of the attachment data
  513. * Returns the offset if seek is successful or -1 on error
  514. */
  515. off64_t libpff_attachment_data_seek_offset(
  516. libpff_item_t *attachment,
  517. off64_t offset,
  518. int whence,
  519. libcerror_error_t **error )
  520. {
  521. libpff_internal_item_t *internal_item = NULL;
  522. libpff_record_entry_t *record_entry = NULL;
  523. static char *function = "libpff_attachment_data_seek_offset";
  524. uint32_t value_type = 0;
  525. int result = 0;
  526. if( attachment == NULL )
  527. {
  528. libcerror_error_set(
  529. error,
  530. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  531. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  532. "%s: invalid attachment.",
  533. function );
  534. return( -1 );
  535. }
  536. internal_item = (libpff_internal_item_t *) attachment;
  537. if( internal_item->internal_file == NULL )
  538. {
  539. libcerror_error_set(
  540. error,
  541. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  542. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  543. "%s: invalid attachment - missing internal file.",
  544. function );
  545. return( -1 );
  546. }
  547. if( internal_item->item_values == NULL )
  548. {
  549. libcerror_error_set(
  550. error,
  551. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  552. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  553. "%s: invalid attachment - missing item values.",
  554. function );
  555. return( -1 );
  556. }
  557. result = libpff_item_values_get_record_entry_by_type(
  558. internal_item->item_values,
  559. internal_item->internal_file->name_to_id_map_list,
  560. internal_item->internal_file->io_handle,
  561. internal_item->file_io_handle,
  562. internal_item->internal_file->offsets_index,
  563. 0,
  564. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT,
  565. 0,
  566. &record_entry,
  567. LIBPFF_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE,
  568. error );
  569. if( result != 1 )
  570. {
  571. libcerror_error_set(
  572. error,
  573. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  574. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  575. "%s: unable to retrieve record entry.",
  576. function );
  577. return( -1 );
  578. }
  579. if( libpff_record_entry_get_value_type(
  580. record_entry,
  581. &value_type,
  582. error ) != 1 )
  583. {
  584. libcerror_error_set(
  585. error,
  586. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  587. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  588. "%s: unable to retrieve value type.",
  589. function );
  590. return( -1 );
  591. }
  592. /* The OLE attachment method could refer to an OLE embedded object
  593. */
  594. if( value_type == LIBPFF_VALUE_TYPE_OBJECT )
  595. {
  596. if( internal_item->embedded_object_data_stream == NULL )
  597. {
  598. if( libpff_internal_item_get_embedded_object_data(
  599. internal_item,
  600. record_entry,
  601. error ) == -1 )
  602. {
  603. libcerror_error_set(
  604. error,
  605. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  606. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  607. "%s: unable to retrieve embedded object data.",
  608. function );
  609. return( -1 );
  610. }
  611. }
  612. offset = libfdata_stream_seek_offset(
  613. internal_item->embedded_object_data_stream,
  614. offset,
  615. whence,
  616. error );
  617. if( offset == -1 )
  618. {
  619. libcerror_error_set(
  620. error,
  621. LIBCERROR_ERROR_DOMAIN_IO,
  622. LIBCERROR_IO_ERROR_SEEK_FAILED,
  623. "%s: unable to seek offset in embedded object data stream.",
  624. function );
  625. return( -1 );
  626. }
  627. }
  628. else
  629. {
  630. offset = libpff_record_entry_seek_offset(
  631. record_entry,
  632. offset,
  633. whence,
  634. error );
  635. if( offset == -1 )
  636. {
  637. libcerror_error_set(
  638. error,
  639. LIBCERROR_ERROR_DOMAIN_IO,
  640. LIBCERROR_IO_ERROR_SEEK_FAILED,
  641. "%s: unable to seek offset in record entry.",
  642. function );
  643. return( -1 );
  644. }
  645. }
  646. return( offset );
  647. }
  648. /* Retrieves the attachment data file IO handle
  649. * Returns 1 if successful, 0 if not available or -1 on error
  650. */
  651. int libpff_attachment_get_data_file_io_handle(
  652. libpff_item_t *attachment,
  653. libbfio_handle_t **file_io_handle,
  654. libcerror_error_t **error )
  655. {
  656. libpff_attached_file_io_handle_t *io_handle = NULL;
  657. static char *function = "libpff_attachment_get_data_file_io_handle";
  658. if( libpff_attached_file_io_handle_initialize(
  659. &io_handle,
  660. attachment,
  661. error ) != 1 )
  662. {
  663. libcerror_error_set(
  664. error,
  665. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  666. LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
  667. "%s: unable to create attached file IO handle.",
  668. function );
  669. goto on_error;
  670. }
  671. if( libbfio_handle_initialize(
  672. file_io_handle,
  673. (intptr_t *) io_handle,
  674. (int (*)(intptr_t **, libcerror_error_t **)) libpff_attached_file_io_handle_free,
  675. (int (*)(intptr_t **, intptr_t *, libcerror_error_t **)) libpff_attached_file_io_handle_clone,
  676. (int (*)(intptr_t *, int flags, libcerror_error_t **)) libpff_attached_file_io_handle_open,
  677. (int (*)(intptr_t *, libcerror_error_t **)) libpff_attached_file_io_handle_close,
  678. (ssize_t (*)(intptr_t *, uint8_t *, size_t, libcerror_error_t **)) libpff_attached_file_io_handle_read,
  679. (ssize_t (*)(intptr_t *, const uint8_t *, size_t, libcerror_error_t **)) libpff_attached_file_io_handle_write,
  680. (off64_t (*)(intptr_t *, off64_t, int, libcerror_error_t **)) libpff_attached_file_io_handle_seek_offset,
  681. (int (*)(intptr_t *, libcerror_error_t **)) libpff_attached_file_io_handle_exists,
  682. (int (*)(intptr_t *, libcerror_error_t **)) libpff_attached_file_io_handle_is_open,
  683. (int (*)(intptr_t *, size64_t *, libcerror_error_t **)) libpff_attached_file_io_handle_get_size,
  684. LIBBFIO_FLAG_IO_HANDLE_MANAGED | LIBBFIO_FLAG_IO_HANDLE_CLONE_BY_FUNCTION,
  685. error ) != 1 )
  686. {
  687. libcerror_error_set(
  688. error,
  689. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  690. LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
  691. "%s: unable to create file IO handle.",
  692. function );
  693. goto on_error;
  694. }
  695. return( 1 );
  696. on_error:
  697. if( io_handle != NULL )
  698. {
  699. libpff_attached_file_io_handle_free(
  700. &io_handle,
  701. NULL );
  702. }
  703. return( -1 );
  704. }
  705. /* Retrieves the attachment item
  706. * Returns 1 if successful, 0 if not available or -1 on error
  707. */
  708. int libpff_attachment_get_item(
  709. libpff_item_t *attachment,
  710. libpff_item_t **attached_item,
  711. libcerror_error_t **error )
  712. {
  713. libcdata_tree_node_t *embedded_item_tree_node = NULL;
  714. libpff_internal_item_t *internal_item = NULL;
  715. libpff_item_descriptor_t *embedded_item_descriptor = NULL;
  716. libpff_local_descriptor_value_t *local_descriptor_value = NULL;
  717. libpff_record_entry_t *record_entry = NULL;
  718. libpff_record_set_t *record_set = NULL;
  719. uint8_t *value_data = NULL;
  720. static char *function = "libpff_attachment_get_item";
  721. size_t value_data_size = 0;
  722. uint32_t embedded_object_item_identifier = 0;
  723. int number_of_sub_nodes = 0;
  724. int has_attachment_data = 0;
  725. int result = 0;
  726. if( attachment == NULL )
  727. {
  728. libcerror_error_set(
  729. error,
  730. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  731. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  732. "%s: invalid attachment.",
  733. function );
  734. return( -1 );
  735. }
  736. internal_item = (libpff_internal_item_t *) attachment;
  737. if( internal_item->internal_file == NULL )
  738. {
  739. libcerror_error_set(
  740. error,
  741. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  742. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  743. "%s: invalid attachment - missing internal file.",
  744. function );
  745. return( -1 );
  746. }
  747. if( internal_item->item_values == NULL )
  748. {
  749. libcerror_error_set(
  750. error,
  751. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  752. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  753. "%s: invalid attachment - missing item values.",
  754. function );
  755. return( -1 );
  756. }
  757. if( attached_item == NULL )
  758. {
  759. libcerror_error_set(
  760. error,
  761. LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
  762. LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
  763. "%s: invalid attached item.",
  764. function );
  765. return( -1 );
  766. }
  767. if( *attached_item != NULL )
  768. {
  769. libcerror_error_set(
  770. error,
  771. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  772. LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
  773. "%s: invalid attached item already set.",
  774. function );
  775. return( -1 );
  776. }
  777. if( libpff_item_get_record_set_by_index(
  778. attachment,
  779. 0,
  780. &record_set,
  781. error ) != 1 )
  782. {
  783. libcerror_error_set(
  784. error,
  785. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  786. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  787. "%s: unable to retrieve record set: 0.",
  788. function );
  789. goto on_error;
  790. }
  791. if( libpff_record_set_get_entry_by_type(
  792. record_set,
  793. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT,
  794. 0,
  795. &record_entry,
  796. LIBPFF_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE,
  797. error ) != 1 )
  798. {
  799. libcerror_error_set(
  800. error,
  801. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  802. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  803. "%s: unable to retrieve record entry: 0x%04 " PRIx32 ".",
  804. function,
  805. LIBPFF_ENTRY_TYPE_ATTACHMENT_DATA_OBJECT );
  806. goto on_error;
  807. }
  808. if( libpff_record_entry_get_value_data(
  809. record_entry,
  810. &value_data,
  811. &value_data_size,
  812. error ) != 1 )
  813. {
  814. libcerror_error_set(
  815. error,
  816. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  817. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  818. "%s: unable to retrieve value data.",
  819. function );
  820. goto on_error;
  821. }
  822. if( value_data != NULL )
  823. {
  824. /* The descriptor identifier is located in the local descriptors tree
  825. */
  826. byte_stream_copy_to_uint32_little_endian(
  827. value_data,
  828. embedded_object_item_identifier );
  829. /* TODO add support for recovered embedded items */
  830. result = libpff_item_tree_get_tree_node_by_identifier(
  831. internal_item->internal_file->item_tree_root_node,
  832. embedded_object_item_identifier,
  833. &embedded_item_tree_node,
  834. error );
  835. if( result == -1 )
  836. {
  837. libcerror_error_set(
  838. error,
  839. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  840. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  841. "%s: unable to retrieve descriptor index value of attached item: %" PRIu32 ".",
  842. function,
  843. embedded_object_item_identifier );
  844. goto on_error;
  845. }
  846. if( result == 0 )
  847. {
  848. result = libpff_item_values_get_local_descriptors_value_by_identifier(
  849. internal_item->item_values,
  850. internal_item->file_io_handle,
  851. embedded_object_item_identifier,
  852. &local_descriptor_value,
  853. error );
  854. if( result == -1 )
  855. {
  856. libcerror_error_set(
  857. error,
  858. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  859. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  860. "%s: unable to retrieve local descriptor identifier: %" PRIu32 ".",
  861. function,
  862. embedded_object_item_identifier );
  863. goto on_error;
  864. }
  865. /* TODO error tollerability flag an attachment as missing if result == 0 */
  866. else if( result == 0 )
  867. {
  868. libcerror_error_set(
  869. error,
  870. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  871. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  872. "%s: missing local descriptor identifier: %" PRIu32 ".",
  873. function,
  874. embedded_object_item_identifier );
  875. goto on_error;
  876. }
  877. if( local_descriptor_value == NULL )
  878. {
  879. libcerror_error_set(
  880. error,
  881. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  882. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  883. "%s: invalid local descriptor value.",
  884. function );
  885. goto on_error;
  886. }
  887. #if defined( HAVE_DEBUG_OUTPUT )
  888. if( libcnotify_verbose != 0 )
  889. {
  890. libcnotify_printf(
  891. "%s: local descriptor identifier: %" PRIu64 " (%s), data: %" PRIu64 ", local descriptors: %" PRIu64 "\n",
  892. function,
  893. local_descriptor_value->identifier,
  894. libpff_debug_get_node_identifier_type(
  895. (uint8_t) ( local_descriptor_value->identifier & 0x0000001fUL ) ),
  896. local_descriptor_value->data_identifier,
  897. local_descriptor_value->local_descriptors_identifier );
  898. }
  899. #endif
  900. /* Make the embedded item the sub item of the attachment
  901. */
  902. if( libpff_item_tree_append_identifier(
  903. internal_item->item_tree_node,
  904. embedded_object_item_identifier,
  905. local_descriptor_value->data_identifier,
  906. local_descriptor_value->local_descriptors_identifier,
  907. internal_item->item_values->recovered,
  908. error ) != 1 )
  909. {
  910. libcerror_error_set(
  911. error,
  912. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  913. LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
  914. "%s: unable to append attached item: %" PRIu32 " to attachment item tree node.",
  915. function,
  916. embedded_object_item_identifier );
  917. goto on_error;
  918. }
  919. if( libcdata_tree_node_get_number_of_sub_nodes(
  920. internal_item->item_tree_node,
  921. &number_of_sub_nodes,
  922. error ) != 1 )
  923. {
  924. libcerror_error_set(
  925. error,
  926. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  927. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  928. "%s: unable to retrieve number of sub nodes.",
  929. function );
  930. goto on_error;
  931. }
  932. /* Only a single embedded item per attachment should exists
  933. */
  934. if( number_of_sub_nodes != 1 )
  935. {
  936. libcerror_error_set(
  937. error,
  938. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  939. LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
  940. "%s: invalid number of sub nodes value out of bounds.",
  941. function );
  942. goto on_error;
  943. }
  944. if( libcdata_tree_node_get_sub_node_by_index(
  945. internal_item->item_tree_node,
  946. 0,
  947. &embedded_item_tree_node,
  948. error ) != 1 )
  949. {
  950. libcerror_error_set(
  951. error,
  952. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  953. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  954. "%s: unable to retrieve first sub node.",
  955. function );
  956. goto on_error;
  957. }
  958. }
  959. if( libcdata_tree_node_get_value(
  960. embedded_item_tree_node,
  961. (intptr_t **) &embedded_item_descriptor,
  962. error ) != 1 )
  963. {
  964. libcerror_error_set(
  965. error,
  966. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  967. LIBCERROR_RUNTIME_ERROR_GET_FAILED,
  968. "%s: unable to retrieve embedded item descriptor.",
  969. function );
  970. goto on_error;
  971. }
  972. if( libpff_item_initialize(
  973. attached_item,
  974. internal_item->file_io_handle,
  975. internal_item->internal_file,
  976. embedded_item_tree_node,
  977. embedded_item_descriptor,
  978. LIBPFF_ITEM_FLAGS_DEFAULT,
  979. error ) != 1 )
  980. {
  981. libcerror_error_set(
  982. error,
  983. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  984. LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
  985. "%s: unable to create attached item.",
  986. function );
  987. goto on_error;
  988. }
  989. if( *attached_item == NULL )
  990. {
  991. libcerror_error_set(
  992. error,
  993. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  994. LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
  995. "%s: invalid attached item.",
  996. function );
  997. goto on_error;
  998. }
  999. has_attachment_data = 1;
  1000. }
  1001. if( libpff_record_entry_free(
  1002. &record_entry,
  1003. error ) != 1 )
  1004. {
  1005. libcerror_error_set(
  1006. error,
  1007. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  1008. LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
  1009. "%s: unable to free record entry.",
  1010. function );
  1011. goto on_error;
  1012. }
  1013. if( libpff_record_set_free(
  1014. &record_set,
  1015. error ) != 1 )
  1016. {
  1017. libcerror_error_set(
  1018. error,
  1019. LIBCERROR_ERROR_DOMAIN_RUNTIME,
  1020. LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
  1021. "%s: unable to free record set.",
  1022. function );
  1023. goto on_error;
  1024. }
  1025. return( has_attachment_data );
  1026. on_error:
  1027. if( record_entry != NULL )
  1028. {
  1029. libpff_record_entry_free(
  1030. &record_entry,
  1031. NULL );
  1032. }
  1033. if( record_set != NULL )
  1034. {
  1035. libpff_record_set_free(
  1036. &record_set,
  1037. NULL );
  1038. }
  1039. return( -1 );
  1040. }