file.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/byte_buf.h>
  6. #include <aws/common/file.h>
  7. #include <aws/common/linked_list.h>
  8. #include <aws/common/logging.h>
  9. #include <aws/common/string.h>
  10. #include <errno.h>
  11. FILE *aws_fopen(const char *file_path, const char *mode) {
  12. if (!file_path || strlen(file_path) == 0) {
  13. AWS_LOGF_ERROR(AWS_LS_COMMON_IO, "static: Failed to open file %s", file_path);
  14. return NULL;
  15. }
  16. struct aws_string *file_path_str = aws_string_new_from_c_str(aws_default_allocator(), file_path);
  17. struct aws_string *mode_str = aws_string_new_from_c_str(aws_default_allocator(), mode);
  18. FILE *file = aws_fopen_safe(file_path_str, mode_str);
  19. aws_string_destroy(mode_str);
  20. aws_string_destroy(file_path_str);
  21. return file;
  22. }
  23. int aws_byte_buf_init_from_file(struct aws_byte_buf *out_buf, struct aws_allocator *alloc, const char *filename) {
  24. AWS_ZERO_STRUCT(*out_buf);
  25. FILE *fp = aws_fopen(filename, "rb");
  26. if (fp) {
  27. if (fseek(fp, 0L, SEEK_END)) {
  28. AWS_LOGF_ERROR(AWS_LS_COMMON_IO, "static: Failed to seek file %s with errno %d", filename, errno);
  29. fclose(fp);
  30. return aws_translate_and_raise_io_error(errno);
  31. }
  32. size_t allocation_size = (size_t)ftell(fp) + 1;
  33. /* Tell the user that we allocate here and if success they're responsible for the free. */
  34. if (aws_byte_buf_init(out_buf, alloc, allocation_size)) {
  35. fclose(fp);
  36. return AWS_OP_ERR;
  37. }
  38. /* Ensure compatibility with null-terminated APIs, but don't consider
  39. * the null terminator part of the length of the payload */
  40. out_buf->len = out_buf->capacity - 1;
  41. out_buf->buffer[out_buf->len] = 0;
  42. if (fseek(fp, 0L, SEEK_SET)) {
  43. AWS_LOGF_ERROR(AWS_LS_COMMON_IO, "static: Failed to seek file %s with errno %d", filename, errno);
  44. aws_byte_buf_clean_up(out_buf);
  45. fclose(fp);
  46. return aws_translate_and_raise_io_error(errno);
  47. }
  48. size_t read = fread(out_buf->buffer, 1, out_buf->len, fp);
  49. fclose(fp);
  50. if (read < out_buf->len) {
  51. AWS_LOGF_ERROR(AWS_LS_COMMON_IO, "static: Failed to read file %s with errno %d", filename, errno);
  52. aws_secure_zero(out_buf->buffer, out_buf->len);
  53. aws_byte_buf_clean_up(out_buf);
  54. return aws_raise_error(AWS_ERROR_SYS_CALL_FAILURE);
  55. }
  56. return AWS_OP_SUCCESS;
  57. }
  58. AWS_LOGF_ERROR(AWS_LS_COMMON_IO, "static: Failed to open file %s with errno %d", filename, errno);
  59. if (errno == 0) {
  60. return aws_raise_error(AWS_ERROR_FILE_INVALID_PATH);
  61. }
  62. return aws_translate_and_raise_io_error(errno);
  63. }
  64. bool aws_is_any_directory_separator(char value) {
  65. return value == '\\' || value == '/';
  66. }
  67. struct aws_directory_iterator {
  68. struct aws_linked_list list_data;
  69. struct aws_allocator *allocator;
  70. struct aws_linked_list_node *current_node;
  71. };
  72. struct directory_entry_value {
  73. struct aws_directory_entry entry;
  74. struct aws_byte_buf path;
  75. struct aws_byte_buf relative_path;
  76. struct aws_linked_list_node node;
  77. };
  78. static bool s_directory_iterator_directory_entry(const struct aws_directory_entry *entry, void *user_data) {
  79. struct aws_directory_iterator *iterator = user_data;
  80. struct directory_entry_value *value = aws_mem_calloc(iterator->allocator, 1, sizeof(struct directory_entry_value));
  81. value->entry = *entry;
  82. aws_byte_buf_init_copy_from_cursor(&value->path, iterator->allocator, entry->path);
  83. value->entry.path = aws_byte_cursor_from_buf(&value->path);
  84. aws_byte_buf_init_copy_from_cursor(&value->relative_path, iterator->allocator, entry->relative_path);
  85. value->entry.relative_path = aws_byte_cursor_from_buf(&value->relative_path);
  86. aws_linked_list_push_back(&iterator->list_data, &value->node);
  87. return true;
  88. }
  89. struct aws_directory_iterator *aws_directory_entry_iterator_new(
  90. struct aws_allocator *allocator,
  91. const struct aws_string *path) {
  92. struct aws_directory_iterator *iterator = aws_mem_acquire(allocator, sizeof(struct aws_directory_iterator));
  93. iterator->allocator = allocator;
  94. aws_linked_list_init(&iterator->list_data);
  95. /* the whole point of this iterator is to avoid recursion, so let's do that by passing recurse as false. */
  96. if (AWS_OP_SUCCESS ==
  97. aws_directory_traverse(allocator, path, false, s_directory_iterator_directory_entry, iterator)) {
  98. if (!aws_linked_list_empty(&iterator->list_data)) {
  99. iterator->current_node = aws_linked_list_front(&iterator->list_data);
  100. }
  101. return iterator;
  102. }
  103. aws_mem_release(allocator, iterator);
  104. return NULL;
  105. }
  106. int aws_directory_entry_iterator_next(struct aws_directory_iterator *iterator) {
  107. struct aws_linked_list_node *node = iterator->current_node;
  108. if (!node || node->next == aws_linked_list_end(&iterator->list_data)) {
  109. return aws_raise_error(AWS_ERROR_LIST_EMPTY);
  110. }
  111. iterator->current_node = aws_linked_list_next(node);
  112. return AWS_OP_SUCCESS;
  113. }
  114. int aws_directory_entry_iterator_previous(struct aws_directory_iterator *iterator) {
  115. struct aws_linked_list_node *node = iterator->current_node;
  116. if (!node || node == aws_linked_list_begin(&iterator->list_data)) {
  117. return aws_raise_error(AWS_ERROR_LIST_EMPTY);
  118. }
  119. iterator->current_node = aws_linked_list_prev(node);
  120. return AWS_OP_SUCCESS;
  121. }
  122. void aws_directory_entry_iterator_destroy(struct aws_directory_iterator *iterator) {
  123. while (!aws_linked_list_empty(&iterator->list_data)) {
  124. struct aws_linked_list_node *node = aws_linked_list_pop_front(&iterator->list_data);
  125. struct directory_entry_value *value = AWS_CONTAINER_OF(node, struct directory_entry_value, node);
  126. aws_byte_buf_clean_up(&value->path);
  127. aws_byte_buf_clean_up(&value->relative_path);
  128. aws_mem_release(iterator->allocator, value);
  129. }
  130. aws_mem_release(iterator->allocator, iterator);
  131. }
  132. const struct aws_directory_entry *aws_directory_entry_iterator_get_value(
  133. const struct aws_directory_iterator *iterator) {
  134. struct aws_linked_list_node *node = iterator->current_node;
  135. if (!iterator->current_node) {
  136. return NULL;
  137. }
  138. struct directory_entry_value *value = AWS_CONTAINER_OF(node, struct directory_entry_value, node);
  139. return &value->entry;
  140. }