manage_signatures.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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. G_debug(1, "I_signatures_remove(%d, %s);", type, name);
  62. /* Remove only if file is in the current mapset */
  63. if (G_name_is_fully_qualified(name, xname, xmapset) &&
  64. strcmp(xmapset, G_mapset()) != 0) {
  65. G_warning(_("%s is not in the current mapset (%s)"), name,
  66. G_mapset());
  67. return 1;
  68. }
  69. if (I_find_signature2(type, name, G_mapset())) {
  70. I_get_signatures_dir(dir, type);
  71. if (G_remove(dir, name) == 1) {
  72. G_verbose_message(_("%s removed"), name);
  73. return 0;
  74. }
  75. G_warning(_("Unable to remove %s signature"), name);
  76. }
  77. else
  78. G_warning(_("%s is missing"), name);
  79. return 1;
  80. }
  81. /*!
  82. * \brief Copy a signature file
  83. *
  84. * If copy fails, prints warning messages and returns 1.
  85. * It is safe to pass fully qualified names.
  86. *
  87. * \param type I_SIGFILE_TYPE signature type
  88. * \param name of old signature
  89. * \param mapset of old signature
  90. * \param name of new signature
  91. * \return 0 on success
  92. * \return 1 on failure
  93. */
  94. int I_signatures_copy(I_SIGFILE_TYPE type, const char *old_name,
  95. const char *old_mapset, const char *new_name)
  96. {
  97. char sname[GNAME_MAX], tname[GNAME_MAX], tmapset[GMAPSET_MAX],
  98. xmapset[GMAPSET_MAX];
  99. char dir[GNAME_MAX];
  100. const char *smapset;
  101. char old_path[GPATH_MAX], new_path[GPATH_MAX];
  102. G_debug(1, "I_signatures_copy(%d, %s@%s, %s);", type, old_name,
  103. old_mapset, new_name);
  104. /* Copy only if mapset of new name is the current mapset */
  105. if (G_name_is_fully_qualified(new_name, tname, tmapset)) {
  106. if (strcmp(tmapset, G_mapset()) != 0) {
  107. G_warning(_("%s is not in the current mapset (%s)"), new_name,
  108. G_mapset());
  109. return 1;
  110. }
  111. }
  112. else
  113. strcat(tname, new_name);
  114. smapset = I_find_signature2(type, old_name, old_mapset);
  115. if (!smapset) {
  116. G_warning(_("%s is missing"), old_name);
  117. return 1;
  118. }
  119. G_unqualified_name(old_name, NULL, sname, xmapset);
  120. I_make_signatures_dir(type);
  121. I_get_signatures_dir(dir, type);
  122. /* Note – we need whole directory not just an element in it thus
  123. G_file_name and not G_file_name_misc */
  124. G_file_name(old_path, dir, sname, smapset);
  125. G_file_name(new_path, dir, tname, G_mapset());
  126. if (G_recursive_copy(old_path, new_path) != 0) {
  127. G_warning(_("Unable to copy <%s> to current mapset as <%s>"),
  128. G_fully_qualified_name(old_name, smapset), tname);
  129. return 1;
  130. }
  131. return 0;
  132. }
  133. /*!
  134. * \brief Rename a signature file
  135. *
  136. * If rename fails, prints warning messages and returns 1.
  137. * It is safe to pass fully qualified names.
  138. *
  139. * \param type I_SIGFILE_TYPE signature type
  140. * \param name of old signature
  141. * \param name of new signature
  142. * \return 0 on success
  143. * \return 1 on failure
  144. */
  145. int I_signatures_rename(I_SIGFILE_TYPE type, const char *old_name,
  146. const char *new_name)
  147. {
  148. char sname[GNAME_MAX], tname[GNAME_MAX], tmapset[GMAPSET_MAX];
  149. char dir[GNAME_MAX];
  150. const char *smapset;
  151. char old_path[GPATH_MAX], new_path[GPATH_MAX];
  152. G_debug(1, "I_signatures_rename(%d, %s, %s);", type, old_name, new_name);
  153. /* Rename only if source and destination mapset is the current mapset */
  154. if (G_name_is_fully_qualified(old_name, sname, tmapset)) {
  155. if (strcmp(tmapset, G_mapset()) != 0) {
  156. G_warning(_("%s is not in the current mapset (%s)"), old_name,
  157. G_mapset());
  158. return 1;
  159. }
  160. }
  161. else
  162. strcat(sname, old_name);
  163. if (G_name_is_fully_qualified(new_name, tname, tmapset)) {
  164. if (strcmp(tmapset, G_mapset()) != 0) {
  165. G_warning(_("%s is not in the current mapset (%s)"), new_name,
  166. G_mapset());
  167. return 1;
  168. }
  169. }
  170. else
  171. strcat(tname, new_name);
  172. smapset = I_find_signature2(type, old_name, tmapset);
  173. if (!smapset) {
  174. G_warning(_("%s is missing"), old_name);
  175. return 1;
  176. }
  177. I_get_signatures_dir(dir, type);
  178. /* Note – we need whole directory not just an element in it thus
  179. G_file_name and not G_file_name_misc */
  180. G_file_name(old_path, dir, sname, tmapset);
  181. G_file_name(new_path, dir, tname, tmapset);
  182. if (G_rename_file(old_path, new_path) != 0) {
  183. G_warning(_("Unable to rename <%s> to <%s>"), old_name, new_name);
  184. return 1;
  185. }
  186. return 0;
  187. }
  188. /*!
  189. * \brief Get list of existing signatures by type
  190. *
  191. * Fills passed list with fully qualified names of existing signatures.
  192. *
  193. * If no mapset is passed, all mapsets in the search path are used.
  194. * If no signatures are found, returns 0 and list is set to NULL.
  195. *
  196. * The function will assign memory for the list. It is up to callee to
  197. * free the memory of each list item and the list itself.
  198. *
  199. * \param type I_SIGFILE_TYPE signature type
  200. * \param mapset optional mapset to search in or NULL
  201. * \param pointer to array of found signature strings or NULL if none found
  202. * \return count of signature strings in the array
  203. */
  204. int I_signatures_list_by_type(I_SIGFILE_TYPE type, const char *mapset,
  205. char ***out_list)
  206. {
  207. int base = 0;
  208. *out_list = NULL;
  209. if (mapset == NULL) {
  210. for (int n = 0; (mapset = G_get_mapset_name(n)); n++) {
  211. base += list_by_type(type, mapset, base, out_list);
  212. }
  213. }
  214. else {
  215. base += list_by_type(type, mapset, base, out_list);
  216. }
  217. return base;
  218. }
  219. /*!
  220. * \brief Free memory allocated by I_signatures_list_by_type
  221. *
  222. * Calls G_free for all list items returned by I_signatures_list_by_type()
  223. * Sets pointer to NULL to prevent accidental use after free.
  224. *
  225. * \param int Return value of I_signatures_list_by_type()
  226. * \param pointer to array filled by I_signatures_list_by_type()
  227. */
  228. void I_free_signatures_list(int count, char ***list)
  229. {
  230. for (int n = 0; n < count; n++) {
  231. G_free((*list)[n]);
  232. }
  233. G_free(*list);
  234. *list = NULL;
  235. }
  236. static int list_by_type(I_SIGFILE_TYPE type, const char *mapset, int base,
  237. char ***out_list)
  238. {
  239. int count = 0;
  240. char path[GPATH_MAX];
  241. char dir[GNAME_MAX];
  242. char **dirlist;
  243. I_get_signatures_dir(dir, type);
  244. G_file_name(path, dir, "", mapset);
  245. if (access(path, 0) != 0) {
  246. return count;
  247. }
  248. dirlist = G_ls2(path, &count);
  249. if (count == 0)
  250. return count;
  251. /* Make items fully qualified names */
  252. int mapset_len = strlen(mapset);
  253. *out_list =
  254. (char **)G_realloc(*out_list, (base + count) * sizeof(char *));
  255. for (int i = 0; i < count; i++) {
  256. (*out_list)[base + i] =
  257. (char *)G_malloc((strlen(dirlist[i]) + 1 + mapset_len + 1) *
  258. sizeof(char));
  259. sprintf((*out_list)[base + i], "%s@%s", dirlist[i], mapset);
  260. }
  261. return count;
  262. }