fs.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 If given path is regular file.
  78. *
  79. * @param [in] path Filesystem path.
  80. * @return 0 - success, < 0 on error.
  81. */
  82. bool_t faux_isfile(const char *path)
  83. {
  84. struct stat statbuf = {};
  85. assert(path);
  86. if (!path)
  87. return BOOL_FALSE;
  88. if (stat(path, &statbuf) < 0)
  89. return BOOL_FALSE;
  90. if (S_ISREG(statbuf.st_mode))
  91. return BOOL_TRUE;
  92. return BOOL_FALSE;
  93. }
  94. /** @brief Removes filesystem objects recursively.
  95. *
  96. * Function can remove file or directory (recursively).
  97. *
  98. * @param [in] path File/directory name.
  99. * @return BOOL_TRUE - success, BOOL_FALSE on error.
  100. */
  101. bool_t faux_rm(const char *path)
  102. {
  103. DIR *dir = NULL;
  104. struct dirent *dir_entry = NULL;
  105. assert(path);
  106. if (!path)
  107. return BOOL_FALSE;
  108. // Common file (not dir)
  109. if (!faux_isdir(path)) {
  110. if (unlink(path) < 0)
  111. return BOOL_FALSE;
  112. return BOOL_TRUE;
  113. }
  114. // Directory
  115. if ((dir = opendir(path)) == NULL)
  116. return BOOL_FALSE;
  117. while ((dir_entry = readdir(dir))) {
  118. if (!strcmp(dir_entry->d_name, ".") ||
  119. !strcmp(dir_entry->d_name, ".."))
  120. continue;
  121. faux_rm(dir_entry->d_name);
  122. }
  123. closedir(dir);
  124. if (rmdir(path) < 0)
  125. return BOOL_FALSE;
  126. return BOOL_TRUE;
  127. }
  128. /** @brief Expand tilde within path due to HOME env var.
  129. *
  130. * If first character of path is tilde then expand it to value of
  131. * environment variable HOME. If tilde is not the first character or
  132. * HOME is not defined then return copy of original path.
  133. *
  134. * @warning The resulting string must be freed by faux_str_free() later.
  135. *
  136. * @param [in] path Path to expand.
  137. * @return Expanded string or NULL on error.
  138. */
  139. char *faux_expand_tilde(const char *path)
  140. {
  141. char *home_dir = getenv("HOME");
  142. char *result = NULL;
  143. assert(path);
  144. if (!path)
  145. return NULL;
  146. // Tilde can be the first character only to be expanded
  147. if (home_dir && (path[0] == '~'))
  148. result = faux_str_sprintf("%s%s", home_dir, &path[1]);
  149. else
  150. result = faux_str_dup(path);
  151. return result;
  152. }