file.c 7.1 KB

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