write_data.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. #define MIN_MSG_SIZE (sizeof(uint64_t) + 1)
  8. #define MAX_MSG_SIZE (100 * 1024 * 1024)
  9. #define ERR_MORE_MSG -1
  10. #define ERR_DONE 0
  11. #define ERR_READ_MSG_SIZE 1
  12. #define ERR_MSG_SIZE 2
  13. #define ERR_OPEN_FILE 3
  14. #define ERR_DATA 4
  15. #define ERR_IO_OPEN 5
  16. #define ERR_IO_SEEK 6
  17. #define ERR_IO_WRITE 7
  18. #define ERR_IO_CLOSE 8
  19. #define ERR_NO_MEM 9
  20. #define ERR_INVALID_ARGS 10
  21. #define ERR_READ_MSG_ID 11
  22. int write_msg_id(uint32_t msg_id)
  23. {
  24. size_t c = fwrite(&msg_id, 1, sizeof(msg_id), stdout);
  25. if (c != sizeof(msg_id))
  26. return ERR_IO_WRITE;
  27. if(fflush(stdout))
  28. return ERR_IO_WRITE;
  29. return ERR_DONE;
  30. }
  31. int handle_msg(FILE* input_stream)
  32. {
  33. uint32_t msg_id = 0;
  34. size_t c = fread(&msg_id, 1, sizeof(uint32_t), input_stream);
  35. if (c != sizeof(uint32_t))
  36. return ERR_READ_MSG_ID;
  37. uint32_t msg_size = 0;
  38. c = fread(&msg_size, 1, sizeof(uint32_t), input_stream);
  39. if (c != sizeof(uint32_t))
  40. return ERR_READ_MSG_SIZE;
  41. if (!msg_size)
  42. {
  43. int err = write_msg_id(msg_id);
  44. if(err)
  45. return err;
  46. return ERR_DONE;
  47. }
  48. if (msg_size < MIN_MSG_SIZE || msg_size > MAX_MSG_SIZE)
  49. return ERR_MSG_SIZE;
  50. unsigned char* buf = (unsigned char*)malloc(msg_size);
  51. if (!buf)
  52. return ERR_NO_MEM;
  53. c = fread(buf, 1, msg_size, input_stream);
  54. if (c != msg_size)
  55. return ERR_IO_OPEN;
  56. char* path = (char*)buf;
  57. // strlen is unsafe
  58. unsigned char* data = (unsigned char*)memchr(path, '\0', msg_size);
  59. if (!data)
  60. return ERR_DATA;
  61. data++;
  62. uint64_t offset = *((uint64_t*)data);
  63. data += sizeof(uint64_t);
  64. // Create an empty file in case it does not exist
  65. FILE* f = fopen(path, "ab+");
  66. if (!f)
  67. return ERR_OPEN_FILE;
  68. if (fclose(f))
  69. return ERR_IO_CLOSE;
  70. // Use rb+ to allow fseek when writing
  71. f = fopen(path, "rb+");
  72. if (!f)
  73. return ERR_OPEN_FILE;
  74. if (fseek(f, (long)offset, SEEK_SET))
  75. return ERR_IO_SEEK;
  76. size_t data_size = msg_size - (data - buf);
  77. c = fwrite(data, 1, data_size, f);
  78. if (c != data_size)
  79. return ERR_IO_WRITE;
  80. if (fclose(f))
  81. return ERR_IO_CLOSE;
  82. // TODO: free also in case of errors
  83. free(buf);
  84. int err = write_msg_id(msg_id);
  85. if(err)
  86. return err;
  87. return ERR_MORE_MSG;
  88. }
  89. int main(int argc, char **argv)
  90. {
  91. FILE* input_stream = NULL;
  92. if (argc == 2)
  93. {
  94. char* input_path = argv[1];
  95. if (!(input_stream = fopen(input_path, "rb")))
  96. return ERR_IO_OPEN;
  97. }
  98. else if (argc == 1)
  99. input_stream = stdin;
  100. else
  101. return ERR_INVALID_ARGS;
  102. int err;
  103. while ((err = handle_msg(input_stream)) == ERR_MORE_MSG);
  104. if (input_stream != stdin)
  105. fclose(input_stream);
  106. return err;
  107. }