manage_signatures.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*!
  2. \file lib/imagery/manage_sinatures.c
  3. \brief Imagery Library - Signature file management functions
  4. (C) 2021 by Maris Nartiss and the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Maris Nartiss
  8. */
  9. #include <unistd.h>
  10. #include <string.h>
  11. #include <grass/gis.h>
  12. #include <grass/imagery.h>
  13. #include <grass/glocale.h>
  14. /*!
  15. \brief Get signature directory
  16. The directory will be in a form "signatures/<type>".
  17. \param dir [GNAME_MAX] allocated string buffer
  18. \param type I_SIGFILE_TYPE
  19. */
  20. void I_get_signatures_dir(char *dir, I_SIGFILE_TYPE type)
  21. {
  22. if (type == I_SIGFILE_TYPE_SIG) {
  23. sprintf(dir, "signatures%csig", HOST_DIRSEP);
  24. }
  25. else if (type == I_SIGFILE_TYPE_SIGSET) {
  26. sprintf(dir, "signatures%csigset", HOST_DIRSEP);
  27. }
  28. else {
  29. G_fatal_error("Programming error: unknown signature file type");
  30. }
  31. }
  32. /*!
  33. \brief Make signature dir
  34. Creates directories for storage of signature files of specified type.
  35. E.g. "<location>/<mapset>/signatures/<type>/"
  36. \param type I_SIGFILE_TYPE
  37. */
  38. void I_make_signatures_dir(I_SIGFILE_TYPE type)
  39. {
  40. char dir[GNAME_MAX];
  41. G_make_mapset_object_group("signatures");
  42. I_get_signatures_dir(dir, type);
  43. G_make_mapset_object_group(dir);
  44. }
  45. static int list_by_type(I_SIGFILE_TYPE, const char *, int, char ***);
  46. /*!
  47. * \brief Remove a signature file
  48. *
  49. * If removal fails, prints a warning and returns 1.
  50. * It is safe to pass fully qualified names.
  51. *
  52. * \param type I_SIGFILE_TYPE signature type
  53. * \param name of signature to remove
  54. * \return 0 on success
  55. * \return 1 on failure
  56. */
  57. int I_signatures_remove(I_SIGFILE_TYPE type, const char *name)
  58. {
  59. char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
  60. char dir[GNAME_MAX];
  61. int ret = 0;
  62. G_debug(1, "I_signatures_remove(%d, %s);", type, name);
  63. /* Remove only if file is in the current mapset */
  64. if (G_name_is_fully_qualified(name, xname, xmapset) &&
  65. strcmp(xmapset, G_mapset()) != 0) {
  66. G_warning(_("%s is not in the current mapset (%s)"), name,
  67. G_mapset());
  68. return 1;
  69. }
  70. if (I_find_signature2(type, name, G_mapset())) {
  71. I_get_signatures_dir(dir, type);
  72. if (G_remove(dir, name) == 1) {
  73. G_verbose_message(_("%s removed"), name);
  74. return 0;
  75. }
  76. G_warning(_("Unable to remove %s signature"), name);
  77. }
  78. else
  79. G_warning(_("%s is missing"), name);
  80. return 1;
  81. }
  82. /*!
  83. * \brief Copy a signature file
  84. *
  85. * If copy fails, prints warning messages and returns 1.
  86. * It is safe to pass fully qualified names.
  87. *
  88. * \param type I_SIGFILE_TYPE signature type
  89. * \param name of old signature
  90. * \param mapset of old signature
  91. * \param name of new signature
  92. * \return 0 on success
  93. * \return 1 on failure
  94. */
  95. int I_signatures_copy(I_SIGFILE_TYPE type, const char *old_name,
  96. const char *old_mapset, const char *new_name)
  97. {
  98. char sname[GNAME_MAX], tname[GNAME_MAX], tmapset[GMAPSET_MAX],
  99. xmapset[GMAPSET_MAX];
  100. char dir[GNAME_MAX];
  101. const char *smapset;
  102. char old_path[GPATH_MAX], new_path[GPATH_MAX];
  103. G_debug(1, "I_signatures_copy(%d, %s@%s, %s);", type, old_name,
  104. old_mapset, new_name);
  105. /* Copy only if mapset of new name is the current mapset */
  106. if (G_name_is_fully_qualified(new_name, tname, tmapset)) {
  107. if (strcmp(tmapset, G_mapset()) != 0) {
  108. G_warning(_("%s is not in the current mapset (%s)"), new_name,
  109. G_mapset());
  110. return 1;
  111. }
  112. }
  113. else
  114. strcat(tname, new_name);
  115. smapset = I_find_signature2(type, old_name, old_mapset);
  116. if (!smapset) {
  117. G_warning(_("%s is missing"), old_name);
  118. return 1;
  119. }
  120. G_unqualified_name(old_name, NULL, sname, xmapset);
  121. I_make_signatures_dir(type);
  122. I_get_signatures_dir(dir, type);
  123. /* Note – we need whole directory not just an element in it thus
  124. G_file_name and not G_file_name_misc */
  125. G_file_name(old_path, dir, sname, smapset);
  126. G_file_name(new_path, dir, tname, G_mapset());
  127. if (G_recursive_copy(old_path, new_path) != 0) {
  128. G_warning(_("Unable to copy <%s> to current mapset as <%s>"),
  129. G_fully_qualified_name(old_name, smapset), tname);
  130. return 1;
  131. }
  132. return 0;
  133. }
  134. /*!
  135. * \brief Rename a signature file
  136. *
  137. * If rename fails, prints warning messages and returns 1.
  138. * It is safe to pass fully qualified names.
  139. *
  140. * \param type I_SIGFILE_TYPE signature type
  141. * \param name of old signature
  142. * \param name of new signature
  143. * \return 0 on success
  144. * \return 1 on failure
  145. */
  146. int I_signatures_rename(I_SIGFILE_TYPE type, const char *old_name,
  147. const char *new_name)
  148. {
  149. char sname[GNAME_MAX], tname[GNAME_MAX], tmapset[GMAPSET_MAX];
  150. char dir[GNAME_MAX];
  151. const char *smapset;
  152. char old_path[GPATH_MAX], new_path[GPATH_MAX];
  153. G_debug(1, "I_signatures_rename(%d, %s, %s);", type, old_name, new_name);
  154. /* Rename only if source and destination mapset is the current mapset */
  155. if (G_name_is_fully_qualified(old_name, sname, tmapset)) {
  156. if (strcmp(tmapset, G_mapset()) != 0) {
  157. G_warning(_("%s is not in the current mapset (%s)"), old_name,
  158. G_mapset());
  159. return 1;
  160. }
  161. }
  162. else
  163. strcat(sname, old_name);
  164. if (G_name_is_fully_qualified(new_name, tname, tmapset)) {
  165. if (strcmp(tmapset, G_mapset()) != 0) {
  166. G_warning(_("%s is not in the current mapset (%s)"), new_name,
  167. G_mapset());
  168. return 1;
  169. }
  170. }
  171. else
  172. strcat(tname, new_name);
  173. smapset = I_find_signature2(type, old_name, tmapset);
  174. if (!smapset) {
  175. G_warning(_("%s is missing"), old_name);
  176. return 1;
  177. }
  178. I_get_signatures_dir(dir, type);
  179. /* Note – we need whole directory not just an element in it thus
  180. G_file_name and not G_file_name_misc */
  181. G_file_name(old_path, dir, sname, tmapset);
  182. G_file_name(new_path, dir, tname, tmapset);
  183. if (G_rename_file(old_path, new_path) != 0) {
  184. G_warning(_("Unable to rename <%s> to <%s>"), old_name, new_name);
  185. return 1;
  186. }
  187. return 0;
  188. }
  189. /*!
  190. * \brief Get list of existing signatures by type
  191. *
  192. * Fills passed list with fully qualified names of existing signatures.
  193. *
  194. * If no mapset is passed, all mapsets in the search path are used.
  195. * If no signatures are found, returns 0 and list is set to NULL.
  196. *
  197. * The function will assign memory for the list. It is up to callee to
  198. * free the memory of each list item and the list itself.
  199. *
  200. * \param type I_SIGFILE_TYPE signature type
  201. * \param mapset optional mapset to search in or NULL
  202. * \param pointer to array of found signature strings or NULL if none found
  203. * \return count of signature strings in the array
  204. */
  205. int I_signatures_list_by_type(I_SIGFILE_TYPE type, const char *mapset,
  206. char ***out_list)
  207. {
  208. int base = 0;
  209. *out_list = NULL;
  210. if (mapset == NULL) {
  211. for (int n = 0; (mapset = G_get_mapset_name(n)); n++) {
  212. base += list_by_type(type, mapset, base, out_list);
  213. }
  214. }
  215. else {
  216. base += list_by_type(type, mapset, base, out_list);
  217. }
  218. return base;
  219. }
  220. /*!
  221. * \brief Free memory allocated by I_signatures_list_by_type
  222. *
  223. * Calls G_free for all list items returned by I_signatures_list_by_type()
  224. * Sets pointer to NULL to prevent accidental use after free.
  225. *
  226. * \param int Return value of I_signatures_list_by_type()
  227. * \param pointer to array filled by I_signatures_list_by_type()
  228. */
  229. void I_free_signatures_list(int count, char ***list)
  230. {
  231. for (int n = 0; n < count; n++) {
  232. G_free((*list)[n]);
  233. }
  234. G_free(*list);
  235. *list = NULL;
  236. }
  237. static int list_by_type(I_SIGFILE_TYPE type, const char *mapset, int base,
  238. char ***out_list)
  239. {
  240. int count = 0;
  241. char path[GPATH_MAX];
  242. char dir[GNAME_MAX];
  243. char **dirlist;
  244. I_get_signatures_dir(dir, type);
  245. G_file_name(path, dir, "", mapset);
  246. if (access(path, 0) != 0) {
  247. return count;
  248. }
  249. dirlist = G_ls2(path, &count);
  250. if (count == 0)
  251. return count;
  252. /* Make items fully qualified names */
  253. int mapset_len = strlen(mapset);
  254. *out_list =
  255. (char **)G_realloc(*out_list, (base + count) * sizeof(char *));
  256. for (int i = 0; i < count; i++) {
  257. (*out_list)[base + i] =
  258. (char *)G_malloc((strlen(dirlist[i]) + 1 + mapset_len + 1) *
  259. sizeof(char));
  260. sprintf((*out_list)[base + i], "%s@%s", dirlist[i], mapset);
  261. }
  262. return count;
  263. }