cmd_file.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. *******************************************************************************
  3. \file cmd_file.c
  4. \brief Command-line interface to Bee2: file management
  5. \project bee2/cmd
  6. \created 2022.06.08
  7. \version 2023.06.23
  8. \copyright The Bee2 authors
  9. \license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
  10. *******************************************************************************
  11. */
  12. #include "../cmd.h"
  13. #include <bee2/core/blob.h>
  14. #include <bee2/core/err.h>
  15. #include <bee2/core/mem.h>
  16. #include <bee2/core/str.h>
  17. #include <bee2/core/util.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. /*
  21. *******************************************************************************
  22. Размер файла
  23. *******************************************************************************
  24. */
  25. size_t cmdFileSize(const char* file)
  26. {
  27. FILE* fp;
  28. long size;
  29. ASSERT(strIsValid(file));
  30. if (!(fp = fopen(file, "rb")))
  31. return SIZE_MAX;
  32. if (fseek(fp, 0, SEEK_END))
  33. {
  34. fclose(fp);
  35. return SIZE_MAX;
  36. }
  37. size = ftell(fp);
  38. fclose(fp);
  39. return (size == -1L) ? SIZE_MAX : (size_t)size;
  40. }
  41. /*
  42. *******************************************************************************
  43. Чтение / запись
  44. *******************************************************************************
  45. */
  46. err_t cmdFileWrite(const char* file, const void* buf, size_t count)
  47. {
  48. err_t code;
  49. FILE* fp;
  50. // pre
  51. ASSERT(strIsValid(file));
  52. ASSERT(memIsValid(buf, count));
  53. // записать
  54. code = (fp = fopen(file, "wb")) ? ERR_OK : ERR_FILE_CREATE;
  55. ERR_CALL_CHECK(code);
  56. code = count == fwrite(buf, 1, count, fp) ? ERR_OK : ERR_FILE_WRITE;
  57. fclose(fp);
  58. // завершить
  59. return code;
  60. }
  61. err_t cmdFileAppend(const char* file, const void* buf, size_t count)
  62. {
  63. err_t code;
  64. FILE* fp;
  65. // pre
  66. ASSERT(strIsValid(file));
  67. ASSERT(memIsValid(buf, count));
  68. // записать
  69. code = (fp = fopen(file, "ab")) ? ERR_OK : ERR_FILE_OPEN;
  70. ERR_CALL_CHECK(code);
  71. code = count == fwrite(buf, 1, count, fp) ? ERR_OK : ERR_FILE_WRITE;
  72. fclose(fp);
  73. // завершить
  74. return code;
  75. }
  76. err_t cmdFileReadAll(void* buf, size_t* count, const char* file)
  77. {
  78. err_t code;
  79. // pre
  80. ASSERT(memIsValid(count, O_PER_S));
  81. ASSERT(strIsValid(file));
  82. // читать
  83. if (buf)
  84. {
  85. FILE* fp;
  86. ASSERT(memIsValid(buf, *count));
  87. code = (fp = fopen(file, "rb")) ? ERR_OK : ERR_FILE_OPEN;
  88. ERR_CALL_CHECK(code);
  89. if (fread(buf, 1, *count, fp) != *count || getc(fp) != EOF)
  90. code = ERR_FILE_READ;
  91. fclose(fp);
  92. }
  93. // определить длину файла
  94. else
  95. {
  96. size_t size = cmdFileSize(file);
  97. code = size != SIZE_MAX ? ERR_OK : ERR_FILE_READ;
  98. ERR_CALL_CHECK(code);
  99. *count = size;
  100. }
  101. return code;
  102. }
  103. /*
  104. *******************************************************************************
  105. Дублирование
  106. *******************************************************************************
  107. */
  108. err_t cmdFileDup(const char* ofile, const char* ifile, size_t skip,
  109. size_t count)
  110. {
  111. const size_t buf_size = 4096;
  112. err_t code;
  113. FILE* ifp;
  114. FILE* ofp;
  115. void* buf;
  116. // pre
  117. ASSERT(strIsValid(ifile) && strIsValid(ofile));
  118. // переполнение?
  119. if ((size_t)(long)skip != skip)
  120. return ERR_OVERFLOW;
  121. // открыть входной файл
  122. ifp = fopen(ifile, "rb");
  123. if (!ifp)
  124. return ERR_FILE_OPEN;
  125. // пропустить skip октетов
  126. if (fseek(ifp, (long)skip, SEEK_SET))
  127. {
  128. fclose(ifp);
  129. return ERR_FILE_READ;
  130. }
  131. // открыть выходной файл
  132. ofp = fopen(ofile, "wb");
  133. if (!ofp)
  134. {
  135. fclose(ifp);
  136. return ERR_FILE_CREATE;
  137. }
  138. // подготовить память
  139. code = cmdBlobCreate(buf, buf_size);
  140. ERR_CALL_HANDLE(code, (fclose(ofp), fclose(ifp)));
  141. // дублировать count октетов
  142. if (count != SIZE_MAX)
  143. while (count && code == ERR_OK)
  144. {
  145. size_t c = MIN2(buf_size, count);
  146. if (fread(buf, 1, c, ifp) != c)
  147. code = ERR_FILE_READ;
  148. else if (fwrite(buf, 1, c, ofp) != c)
  149. code = ERR_FILE_WRITE;
  150. count -= c;
  151. }
  152. // дублировать все
  153. else
  154. while (code == ERR_OK)
  155. {
  156. size_t c = fread(buf, 1, buf_size, ifp);
  157. if (c != buf_size && !feof(ifp))
  158. code = ERR_FILE_READ;
  159. else if (fwrite(buf, 1, c, ofp) != c)
  160. code = ERR_FILE_WRITE;
  161. }
  162. // завершить
  163. cmdBlobClose(buf);
  164. fclose(ofp), fclose(ifp);
  165. return code;
  166. }
  167. /*
  168. *******************************************************************************
  169. Проверки
  170. *******************************************************************************
  171. */
  172. err_t cmdFileValNotExist(int count, char* files[])
  173. {
  174. FILE* fp;
  175. int ch;
  176. for (; count--; files++)
  177. {
  178. ASSERT(strIsValid(*files));
  179. if (fp = fopen(*files, "rb"))
  180. {
  181. fclose(fp);
  182. printf("Some files already exist. Overwrite [y/n]?");
  183. do
  184. ch = cmdTermGetch();
  185. while (ch != 'Y' && ch != 'y' && ch != 'N' && ch != 'n' && ch != '\n');
  186. printf("\n");
  187. if (ch == 'N' || ch == 'n' || ch == '\n')
  188. return ERR_FILE_EXISTS;
  189. break;
  190. }
  191. }
  192. return ERR_OK;
  193. }
  194. err_t cmdFileValExist(int count, char* files[])
  195. {
  196. FILE* fp;
  197. for (; count--; files++)
  198. {
  199. ASSERT(strIsValid(*files));
  200. if (!(fp = fopen(*files, "rb")))
  201. return ERR_FILE_NOT_FOUND;
  202. fclose(fp);
  203. }
  204. return ERR_OK;
  205. }
  206. bool_t cmdFileAreSame(const char* file1, const char* file2)
  207. {
  208. bool_t ret;
  209. #ifdef OS_UNIX
  210. char* path1 = realpath(file1, 0);
  211. char* path2 = realpath(file2, 0);
  212. ret = path1 && path2 && strEq(path1, path2);
  213. free(path1), free(path2);
  214. #elif defined OS_WIN
  215. char* path1 = _fullpath(0, file1, 0);
  216. char* path2 = _fullpath(0, file2, 0);
  217. ret = path1 && path2 && strEq(path1, path2);
  218. free(path1), free(path2);
  219. #else
  220. ret = strEq(file1, file2);
  221. #endif
  222. return ret;
  223. }