fs.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /** @file fs.c
  2. * @brief Enchanced base filesystem operations.
  3. */
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <dirent.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include "faux/str.h"
  15. /** @brief Reports size of file or directory.
  16. *
  17. * Function works recursively so directory size is a sum of all file size
  18. * inside it and size of subdirs.
  19. *
  20. * @param [in] path Filesystem path.
  21. * @return Size of filesystem object or < 0 on error.
  22. */
  23. ssize_t faux_filesize(const char *path)
  24. {
  25. struct stat statbuf = {};
  26. DIR *dir = NULL;
  27. struct dirent *entry = NULL;
  28. ssize_t sum = 0;
  29. assert(path);
  30. if (!path)
  31. return -1;
  32. if (stat(path, &statbuf) < 0)
  33. return -1;
  34. // Regular file
  35. if (!S_ISDIR(statbuf.st_mode))
  36. return statbuf.st_size;
  37. // Directory
  38. dir = opendir(path);
  39. if (!dir)
  40. return -1;
  41. // Get each file from 'path' directory
  42. for (entry = readdir(dir); entry; entry = readdir(dir)) {
  43. char *fn = NULL;
  44. ssize_t r = 0;
  45. // Ignore "." and ".."
  46. if ((faux_str_casecmp(entry->d_name, ".") == 0) ||
  47. (faux_str_casecmp(entry->d_name, "..") == 0))
  48. continue;
  49. // Construct filename
  50. fn = faux_str_sprintf("%s/%s", path, entry->d_name);
  51. r = faux_filesize(fn);
  52. faux_str_free(fn);
  53. if (r < 0)
  54. continue;
  55. sum += r;
  56. }
  57. closedir(dir);
  58. return sum;
  59. }
  60. /** @brief If given path is directory.
  61. *
  62. * @param [in] path Filesystem path.
  63. * @return 0 - success, < 0 on error.
  64. */
  65. bool_t faux_isdir(const char *path)
  66. {
  67. struct stat statbuf = {};
  68. assert(path);
  69. if (!path)
  70. return BOOL_FALSE;
  71. if (stat(path, &statbuf) < 0)
  72. return BOOL_FALSE;
  73. if (S_ISDIR(statbuf.st_mode))
  74. return BOOL_TRUE;
  75. return BOOL_FALSE;
  76. }
  77. /** @brief Removes filesystem objects recursively.
  78. *
  79. * Function can remove file or directory (recursively).
  80. *
  81. * @param [in] path File/directory name.
  82. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  83. */
  84. bool_t faux_rm(const char *path)
  85. {
  86. DIR *dir = NULL;
  87. struct dirent *dir_entry = NULL;
  88. assert(path);
  89. if (!path)
  90. return BOOL_FALSE;
  91. // Common file (not dir)
  92. if (!faux_isdir(path)) {
  93. if (unlink(path) < 0)
  94. return BOOL_FALSE;
  95. return BOOL_TRUE;
  96. }
  97. // Directory
  98. if ((dir = opendir(path)) == NULL)
  99. return BOOL_FALSE;
  100. while ((dir_entry = readdir(dir))) {
  101. if (!strcmp(dir_entry->d_name, ".") ||
  102. !strcmp(dir_entry->d_name, ".."))
  103. continue;
  104. faux_rm(dir_entry->d_name);
  105. }
  106. closedir(dir);
  107. if (rmdir(path) < 0)
  108. return BOOL_FALSE;
  109. return BOOL_TRUE;
  110. }
  111. /** @brief Expand tilde within path due to HOME env var.
  112. *
  113. * If first character of path is tilde then expand it to value of
  114. * environment variable HOME. If tilde is not the first character or
  115. * HOME is not defined then return copy of original path.
  116. *
  117. * @warning The resulting string must be freed by faux_str_free() later.
  118. *
  119. * @param [in] path Path to expand.
  120. * @return Expanded string or NULL on error.
  121. */
  122. char *faux_expand_tilde(const char *path)
  123. {
  124. char *home_dir = getenv("HOME");
  125. char *result = NULL;
  126. assert(path);
  127. if (!path)
  128. return NULL;
  129. // Tilde can be the first character only to be expanded
  130. if (home_dir && (path[0] == '~'))
  131. result = faux_str_sprintf("%s%s", home_dir, &path[1]);
  132. else
  133. result = faux_str_dup(path);
  134. return result;
  135. }