write_data.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright 2016 Cloudbase Solutions Srl
  2. // All Rights Reserved.
  3. #include <stdio.h>
  4. #include <stdint.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <zlib.h>
  8. #define MIN_MSG_SIZE (sizeof(uint64_t) + 1)
  9. #define MAX_MSG_SIZE (100 * 1024 * 1024)
  10. #define ERR_MORE_MSG -1
  11. #define ERR_DONE 0
  12. #define ERR_READ_MSG_SIZE 1
  13. #define ERR_MSG_SIZE 2
  14. #define ERR_OPEN_FILE 3
  15. #define ERR_DATA 4
  16. #define ERR_IO_OPEN 5
  17. #define ERR_IO_SEEK 6
  18. #define ERR_IO_WRITE 7
  19. #define ERR_IO_CLOSE 8
  20. #define ERR_NO_MEM 9
  21. #define ERR_INVALID_ARGS 10
  22. #define ERR_READ_MSG_ID 11
  23. #define ERR_MSG_SIZE_INFLATED 12
  24. #define ERR_ZLIB 13
  25. int write_msg_id(uint32_t msg_id)
  26. {
  27. size_t c = fwrite(&msg_id, 1, sizeof(msg_id), stdout);
  28. if (c != sizeof(msg_id))
  29. return ERR_IO_WRITE;
  30. if(fflush(stdout))
  31. return ERR_IO_WRITE;
  32. return ERR_DONE;
  33. }
  34. int inflate_buf(uint32_t msg_size, void* buf, uint32_t msg_size_inflated,
  35. void* inflated_buf)
  36. {
  37. z_stream strm;
  38. memset(&strm, 0, sizeof(z_stream));
  39. int ret = inflateInit(&strm);
  40. if (ret != Z_OK)
  41. return ERR_ZLIB;
  42. strm.avail_in = msg_size;
  43. strm.next_in = buf;
  44. strm.avail_out = msg_size_inflated;
  45. strm.next_out = inflated_buf;
  46. ret = inflate(&strm, Z_FINISH);
  47. if(ret != Z_STREAM_END)
  48. return ERR_ZLIB;
  49. inflateEnd(&strm);
  50. return ERR_DONE;
  51. }
  52. int handle_msg(FILE* input_stream)
  53. {
  54. uint32_t msg_id = 0;
  55. size_t c = fread(&msg_id, 1, sizeof(uint32_t), input_stream);
  56. if (c != sizeof(uint32_t))
  57. return ERR_READ_MSG_ID;
  58. uint32_t msg_size = 0;
  59. c = fread(&msg_size, 1, sizeof(uint32_t), input_stream);
  60. if (c != sizeof(uint32_t))
  61. return ERR_READ_MSG_SIZE;
  62. if (!msg_size)
  63. {
  64. int err = write_msg_id(msg_id);
  65. if(err)
  66. return err;
  67. return ERR_DONE;
  68. }
  69. if (msg_size < MIN_MSG_SIZE || msg_size > MAX_MSG_SIZE)
  70. return ERR_MSG_SIZE;
  71. uint32_t msg_size_inflated = 0;
  72. c = fread(&msg_size_inflated, 1, sizeof(uint32_t), input_stream);
  73. if (c != sizeof(uint32_t))
  74. return ERR_MSG_SIZE_INFLATED;
  75. if (msg_size_inflated != 0 && (msg_size_inflated < MIN_MSG_SIZE ||
  76. msg_size_inflated > MAX_MSG_SIZE))
  77. return ERR_MSG_SIZE_INFLATED;
  78. unsigned char* buf = (unsigned char*)malloc(msg_size);
  79. if (!buf)
  80. return ERR_NO_MEM;
  81. c = fread(buf, 1, msg_size, input_stream);
  82. if (c != msg_size)
  83. return ERR_IO_OPEN;
  84. if(msg_size_inflated)
  85. {
  86. unsigned char* inflated_buf = (unsigned char*)malloc(msg_size_inflated);
  87. if (!inflated_buf)
  88. return ERR_NO_MEM;
  89. int err = inflate_buf(msg_size, buf, msg_size_inflated, inflated_buf);
  90. if(err != ERR_DONE)
  91. {
  92. free(inflated_buf);
  93. return err;
  94. }
  95. free(buf);
  96. buf = inflated_buf;
  97. msg_size = msg_size_inflated;
  98. }
  99. char* path = (char*)buf;
  100. // strlen is unsafe
  101. unsigned char* data = (unsigned char*)memchr(path, '\0', msg_size);
  102. if (!data)
  103. return ERR_DATA;
  104. data++;
  105. uint64_t offset = *((uint64_t*)data);
  106. data += sizeof(uint64_t);
  107. // Create an empty file in case it does not exist
  108. FILE* f = fopen(path, "ab+");
  109. if (!f)
  110. return ERR_OPEN_FILE;
  111. if (fclose(f))
  112. return ERR_IO_CLOSE;
  113. // Use rb+ to allow fseek when writing
  114. f = fopen(path, "rb+");
  115. if (!f)
  116. return ERR_OPEN_FILE;
  117. if (fseek(f, (long)offset, SEEK_SET))
  118. return ERR_IO_SEEK;
  119. size_t data_size = msg_size - (data - buf);
  120. c = fwrite(data, 1, data_size, f);
  121. if (c != data_size)
  122. return ERR_IO_WRITE;
  123. if (fclose(f))
  124. return ERR_IO_CLOSE;
  125. // TODO: free also in case of errors
  126. free(buf);
  127. int err = write_msg_id(msg_id);
  128. if(err)
  129. return err;
  130. return ERR_MORE_MSG;
  131. }
  132. int main(int argc, char **argv)
  133. {
  134. FILE* input_stream = NULL;
  135. if (argc == 2)
  136. {
  137. char* input_path = argv[1];
  138. if (!(input_stream = fopen(input_path, "rb")))
  139. return ERR_IO_OPEN;
  140. }
  141. else if (argc == 1)
  142. input_stream = stdin;
  143. else
  144. return ERR_INVALID_ARGS;
  145. int err;
  146. while ((err = handle_msg(input_stream)) == ERR_MORE_MSG);
  147. if (input_stream != stdin)
  148. fclose(input_stream);
  149. return err;
  150. }