file.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. struct aws_directory_iterator {
  73. struct aws_linked_list list_data;
  74. struct aws_allocator *allocator;
  75. struct aws_linked_list_node *current_node;
  76. };
  77. struct directory_entry_value {
  78. struct aws_directory_entry entry;
  79. struct aws_byte_buf path;
  80. struct aws_byte_buf relative_path;
  81. struct aws_linked_list_node node;
  82. };
  83. static bool s_directory_iterator_directory_entry(const struct aws_directory_entry *entry, void *user_data) {
  84. struct aws_directory_iterator *iterator = user_data;
  85. struct directory_entry_value *value = aws_mem_calloc(iterator->allocator, 1, sizeof(struct directory_entry_value));
  86. value->entry = *entry;
  87. aws_byte_buf_init_copy_from_cursor(&value->path, iterator->allocator, entry->path);
  88. value->entry.path = aws_byte_cursor_from_buf(&value->path);
  89. aws_byte_buf_init_copy_from_cursor(&value->relative_path, iterator->allocator, entry->relative_path);
  90. value->entry.relative_path = aws_byte_cursor_from_buf(&value->relative_path);
  91. aws_linked_list_push_back(&iterator->list_data, &value->node);
  92. return true;
  93. }
  94. struct aws_directory_iterator *aws_directory_entry_iterator_new(
  95. struct aws_allocator *allocator,
  96. const struct aws_string *path) {
  97. struct aws_directory_iterator *iterator = aws_mem_acquire(allocator, sizeof(struct aws_directory_iterator));
  98. iterator->allocator = allocator;
  99. aws_linked_list_init(&iterator->list_data);
  100. /* the whole point of this iterator is to avoid recursion, so let's do that by passing recurse as false. */
  101. if (AWS_OP_SUCCESS ==
  102. aws_directory_traverse(allocator, path, false, s_directory_iterator_directory_entry, iterator)) {
  103. if (!aws_linked_list_empty(&iterator->list_data)) {
  104. iterator->current_node = aws_linked_list_front(&iterator->list_data);
  105. }
  106. return iterator;
  107. }
  108. aws_mem_release(allocator, iterator);
  109. return NULL;
  110. }
  111. int aws_directory_entry_iterator_next(struct aws_directory_iterator *iterator) {
  112. struct aws_linked_list_node *node = iterator->current_node;
  113. if (!node || node->next == aws_linked_list_end(&iterator->list_data)) {
  114. return aws_raise_error(AWS_ERROR_LIST_EMPTY);
  115. }
  116. iterator->current_node = aws_linked_list_next(node);
  117. return AWS_OP_SUCCESS;
  118. }
  119. int aws_directory_entry_iterator_previous(struct aws_directory_iterator *iterator) {
  120. struct aws_linked_list_node *node = iterator->current_node;
  121. if (!node || node == aws_linked_list_begin(&iterator->list_data)) {
  122. return aws_raise_error(AWS_ERROR_LIST_EMPTY);
  123. }
  124. iterator->current_node = aws_linked_list_prev(node);
  125. return AWS_OP_SUCCESS;
  126. }
  127. void aws_directory_entry_iterator_destroy(struct aws_directory_iterator *iterator) {
  128. while (!aws_linked_list_empty(&iterator->list_data)) {
  129. struct aws_linked_list_node *node = aws_linked_list_pop_front(&iterator->list_data);
  130. struct directory_entry_value *value = AWS_CONTAINER_OF(node, struct directory_entry_value, node);
  131. aws_byte_buf_clean_up(&value->path);
  132. aws_byte_buf_clean_up(&value->relative_path);
  133. aws_mem_release(iterator->allocator, value);
  134. }
  135. aws_mem_release(iterator->allocator, iterator);
  136. }
  137. const struct aws_directory_entry *aws_directory_entry_iterator_get_value(
  138. const struct aws_directory_iterator *iterator) {
  139. struct aws_linked_list_node *node = iterator->current_node;
  140. if (!iterator->current_node) {
  141. return NULL;
  142. }
  143. struct directory_entry_value *value = AWS_CONTAINER_OF(node, struct directory_entry_value, node);
  144. return &value->entry;
  145. }