123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- /*!
- \file lib/vector/Vlib/map.c
-
- \brief Vector library - Manipulate vector map (copy, rename, delete)
-
- Higher level functions for reading/writing/manipulating vectors.
-
- (C) 2001-2009, 2012 by the GRASS Development Team
-
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
-
- \author Original author CERL, probably Dave Gerdes or Mike Higgins.
- \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <dirent.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <grass/glocale.h>
- #include <grass/vector.h>
- #include <grass/dbmi.h>
- #include <grass/glocale.h>
- #include "local_proto.h"
- /*!
- \brief Creates and initializes Map_info structure
- To free allocated memory call Vect_destroy_map_struct().
- \return pointer to Map_info
- */
- struct Map_info *Vect_new_map_struct(void)
- {
- struct Map_info *p;
- p = (struct Map_info *)malloc(sizeof(struct Map_info));
- if (NULL == p)
- G_fatal_error("Vect_new_map_struct(): %s", _("Out of memory"));
- G_zero(p, sizeof(struct Map_info));
- return p;
- }
- /*!
- \brief Frees all memory associated with a Map_info structure,
- including the structure itself
- \param p pointer to Map_info structure
- */
- void Vect_destroy_map_struct(struct Map_info *p)
- {
- /* We should free all allocated member structures, but they may be already
- freed by other functions (e.g. Vect_close()) without resetting member pointers to zero */
- G_free((char *)p);
- }
- /*!
- \brief Copy file
- \param src source file
- \param[out] dst destination file
- \return 0 OK
- \return 1 error
- */
- static int copy_file(const char *src, const char *dst)
- {
- char buf[4096];
- int fd, fd2;
- FILE *f2;
- int len, len2;
- if ((fd = open(src, O_RDONLY)) < 0)
- return 1;
- /* if((fd2 = open(dst, O_CREAT|O_TRUNC|O_WRONLY)) < 0) { */
- if ((f2 = fopen(dst, "w")) == NULL) {
- close(fd);
- return 1;
- }
- fd2 = fileno(f2);
- len2 = 0;
- while ((len = read(fd, buf, 4096)) > 0) {
- while (len && (len2 = write(fd2, buf, len)) >= 0)
- len -= len2;
- }
- close(fd);
- /* close(fd2); */
- fclose(f2);
- if (len == -1 || len2 == -1)
- return 1;
- return 0;
- }
- /*!
- \brief Copy vector map including attribute tables
- Note: Output vector map is overwritten if exists!
- \param in name if vector map to be copied
- \param mapset mapset name where the input map is located
- \param out name for output vector map (new map is created in current mapset)
- \return -1 error
- \return 0 success
- */
- int Vect_copy(const char *in, const char *mapset, const char *out)
- {
- int i, ret;
- struct Map_info In, Out;
- char old_path[GPATH_MAX], new_path[GPATH_MAX], buf[GPATH_MAX];
- const char *files[] = { GV_FRMT_ELEMENT, GV_COOR_ELEMENT,
- GV_HEAD_ELEMENT, GV_HIST_ELEMENT,
- GV_TOPO_ELEMENT, GV_SIDX_ELEMENT, GV_CIDX_ELEMENT,
- NULL
- };
- const char *inmapset;
- char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
- G_debug(2, "Copy vector '%s' in '%s' to '%s'", in, mapset, out);
- /* check for [A-Za-z][A-Za-z0-9_]* in name */
- if (Vect_legal_filename(out) < 0)
- G_fatal_error(_("Vector map name is not SQL compliant"));
- inmapset = G_find_vector2(in, mapset);
- if (!inmapset) {
- G_warning(_("Unable to find vector map <%s> in <%s>"), in, mapset);
- return -1;
- }
- mapset = inmapset;
- /* remove mapset from fully qualified name, confuses G_file_name() */
- if (G_name_is_fully_qualified(in, xname, xmapset)) {
- in = xname;
- }
- /* Delete old vector if it exists */
- if (G_find_vector2(out, G_mapset())) {
- G_warning(_("Vector map <%s> already exists and will be overwritten"),
- out);
- ret = Vect_delete(out);
- if (ret != 0) {
- G_warning(_("Unable to delete vector map <%s>"), out);
- return -1;
- }
- }
- /* Copy the directory */
- G_make_mapset_dir_object(GV_DIRECTORY, out);
- i = 0;
- while (files[i]) {
- sprintf(buf, "%s/%s", in, files[i]);
- G_file_name(old_path, GV_DIRECTORY, buf, mapset);
- sprintf(buf, "%s/%s", out, files[i]);
- G_file_name(new_path, GV_DIRECTORY, buf, G_mapset());
- if (access(old_path, F_OK) == 0) { /* file exists? */
- G_debug(2, "copy %s to %s", old_path, new_path);
- if (copy_file(old_path, new_path)) {
- G_warning(_("Unable to copy vector map <%s> to <%s>"),
- old_path, new_path);
- }
- }
- i++;
- }
- G_file_name(old_path, GV_DIRECTORY, in, mapset);
- G_file_name(new_path, GV_DIRECTORY, out, G_mapset());
- /* Open input */
- Vect_set_open_level(1);
- if (Vect_open_old_head(&In, in, mapset) < 0)
- G_fatal_error(_("Unable to open vector map <%s>"), in);
- if (In.format != GV_FORMAT_NATIVE) { /* Done */
- Vect_close(&In);
- return 0;
- }
- /* Open output */
- Vect_set_open_level(1);
- if (Vect_open_update_head(&Out, out, G_mapset()) < 0)
- G_fatal_error(_("Unable to open vector map <%s>"), out);
- /* Copy tables */
- if (Vect_copy_tables(&In, &Out, 0) != 0) {
- Vect_close(&In);
- Vect_close(&Out);
- return 1;
- }
- Vect_close(&In);
- Vect_close(&Out);
- return 0;
- }
- /*!
- \brief Rename existing vector map (in the current mapset).
- Attribute tables are created in the same database where input tables were stored.
- The origial format (native/OGR) is used.
- Note: Output vector map is overwritten if exists!
- \param in name of vector map to be renamed
- \param out name for output vector map
- \return -1 error
- \return 0 success
- */
- int Vect_rename(const char *in, const char *out)
- {
- int i, n, ret, type;
- struct Map_info Map;
- struct field_info *Fin, *Fout;
- int *fields;
- dbDriver *driver;
- char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
- G_debug(2, "Rename vector '%s' to '%s'", in, out);
- /* check for [A-Za-z][A-Za-z0-9_]* in name */
- if (Vect_legal_filename(out) < 0)
- G_fatal_error(_("Vector map name is not SQL compliant"));
- /* Delete old vector if it exists */
- if (G_find_vector2(out, G_mapset())) {
- G_warning(_("Vector map <%s> already exists and will be overwritten"),
- out);
- Vect_delete(out);
- }
- /* remove mapset from fully qualified name */
- if (G_name_is_fully_qualified(in, xname, xmapset)) {
- in = xname;
- }
- /* Move the directory */
- ret = G_rename(GV_DIRECTORY, in, out);
- if (ret == 0) {
- G_warning(_("Vector map <%s> not found"), in);
- return -1;
- }
- else if (ret == -1) {
- G_warning(_("Unable to copy vector map <%s> to <%s>"), in, out);
- return -1;
- }
- /* Rename all tables if the format is native */
- Vect_set_open_level(1);
- if (Vect_open_update_head(&Map, out, G_mapset()) < 0)
- G_fatal_error(_("Unable to open vector map <%s>"), out);
- if (Map.format != GV_FORMAT_NATIVE) { /* Done */
- Vect_close(&Map);
- return 0;
- }
- /* Copy tables */
- n = Vect_get_num_dblinks(&Map);
- type = GV_1TABLE;
- if (n > 1)
- type = GV_MTABLE;
- /* Make the list of fields */
- fields = (int *)G_malloc(n * sizeof(int));
- for (i = 0; i < n; i++) {
- Fin = Vect_get_dblink(&Map, i);
- fields[i] = Fin->number;
- }
- for (i = 0; i < n; i++) {
- G_debug(3, "field[%d] = %d", i, fields[i]);
- Fin = Vect_get_field(&Map, fields[i]);
- if (Fin == NULL) {
- G_warning(_("Database connection not defined for layer %d"),
- fields[i]);
- Vect_close(&Map);
- return -1;
- }
- Fout = Vect_default_field_info(&Map, Fin->number, Fin->name, type);
- G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'",
- Fin->driver, Fin->database, Fin->table, Fout->driver,
- Fout->database, Fout->table);
- /* TODO: db_rename_table instead of db_copy_table */
- ret = db_copy_table(Fin->driver, Fin->database, Fin->table,
- Fout->driver, Vect_subst_var(Fout->database,
- &Map), Fout->table);
- if (ret == DB_FAILED) {
- G_warning(_("Unable to copy table <%s>"), Fin->table);
- Vect_close(&Map);
- return -1;
- }
- /* Change the link */
- Vect_map_del_dblink(&Map, Fin->number);
- Vect_map_add_dblink(&Map, Fout->number, Fout->name, Fout->table,
- Fin->key, Fout->database, Fout->driver);
- /* Delete old table */
- ret = db_delete_table(Fin->driver, Fin->database, Fin->table);
- if (ret == DB_FAILED) {
- G_warning(_("Unable to delete table <%s>"), Fin->table);
- Vect_close(&Map);
- return -1;
- }
- driver =
- db_start_driver_open_database(Fout->driver,
- Vect_subst_var(Fout->database,
- &Map));
- if (driver == NULL) {
- G_warning(_("Unable to open database <%s> by driver <%s>"),
- Fout->database, Fout->driver);
- }
- else {
- if (db_create_index2(driver, Fout->table, Fin->key) != DB_OK)
- G_warning(_("Unable to create index for table <%s>, key <%s>"),
- Fout->table, Fout->key);
- db_close_database_shutdown_driver(driver);
- }
- }
- Vect_close(&Map);
- free(fields);
- return 0;
- }
- /*!
- \brief Delete vector map including attribute tables
- Vector map must be located in current mapset.
-
- \param map name of vector map to be delete
- \return -1 error
- \return 0 success
- */
- int Vect_delete(const char *map)
- {
- return Vect__delete(map, FALSE);
- }
- /*!
- \brief Delete vector map (internal use only)
-
- \param map name of vector map to be delete
- \param is_tmp TRUE for temporary maps
- \return -1 error
- \return 0 success
- */
- int Vect__delete(const char *map, int is_tmp)
- {
- int ret;
- char path[GPATH_MAX], path_buf[GPATH_MAX];
- char xname[GNAME_MAX], xmapset[GMAPSET_MAX];
- const char *tmp, *mapset, *env;
-
- struct Map_info Map;
-
- DIR *dir;
- struct dirent *ent;
- G_debug(3, "Delete vector '%s' (is_tmp = %d)", map, is_tmp);
- mapset = G_mapset();
-
- /* remove mapset from fully qualified name */
- if (G_name_is_fully_qualified(map, xname, xmapset)) {
- if (strcmp(mapset, xmapset) != 0)
- G_warning(_("Ignoring invalid mapset: %s"), xmapset);
- map = xname;
- }
- if (map == NULL || strlen(map) == 0) {
- G_warning(_("Invalid vector map name <%s>"), map ? map : "null");
- return -1;
- }
- Vect_set_open_level(1); /* Topo not needed */
- ret = Vect__open_old(&Map, map, mapset, NULL, FALSE, TRUE, is_tmp);
- if (ret < 1) {
- if (is_tmp)
- return 0; /* temporary vector map doesn't exist */
- else {
- G_warning(_("Unable to open header file for vector map <%s>"),
- map);
- return -1;
- }
- }
-
- Vect__get_element_path(path, &Map, GV_DBLN_ELEMENT);
- G_debug(1, "dbln file: %s", path);
- if (access(path, F_OK) == 0) {
- int i, n;
- struct field_info *Fi;
-
- /* Delete all tables, NOT external (OGR) */
- if (Map.format == GV_FORMAT_NATIVE) {
- n = Vect_get_num_dblinks(&Map);
- for (i = 0; i < n; i++) {
- Fi = Vect_get_dblink(&Map, i);
- if (Fi == NULL) {
- G_warning(_("Database connection not defined for layer %d"),
- Map.dblnk->field[i].number);
- /*
- Vect_close(&Map);
- return -1;
- */
- continue;
- }
- G_debug(3, "Delete drv:db:table '%s:%s:%s'", Fi->driver,
- Fi->database, Fi->table);
- ret = db_table_exists(Fi->driver, Fi->database, Fi->table);
- if (ret == -1) {
- G_warning(_("Unable to find table <%s> linked to vector map <%s>"),
- Fi->table, map);
- /*
- Vect_close(&Map);
- return -1;
- */
- continue;
- }
- if (ret == 1) {
- ret =
- db_delete_table(Fi->driver, Fi->database, Fi->table);
- if (ret == DB_FAILED) {
- G_warning(_("Unable to delete table <%s>"),
- Fi->table);
- /*
- Vect_close(&Map);
- return -1;
- */
- continue;
- }
- }
- else {
- G_warning(_("Table <%s> linked to vector map <%s> does not exist"),
- Fi->table, map);
- }
- }
- }
- }
-
- /* Delete all files from vector/name directory */
- Vect__get_element_path(path, &Map, NULL);
- Vect_close(&Map);
- G_debug(3, "opendir '%s'", path);
- dir = opendir(path);
- if (dir == NULL) {
- G_warning(_("Unable to open directory '%s'"), path);
- return -1;
- }
- while ((ent = readdir(dir))) {
- G_debug(3, "file = '%s'", ent->d_name);
- if ((strcmp(ent->d_name, ".") == 0) ||
- (strcmp(ent->d_name, "..") == 0))
- continue;
-
- ret = snprintf(path_buf, GPATH_MAX, "%s/%s", path, ent->d_name);
- if (ret >= GPATH_MAX) {
- G_warning(_("Filepath '%s/%s' exceeds max length"), path,
- ent->d_name);
- closedir(dir);
- return -1;
- }
- G_debug(3, "delete file '%s'", path_buf);
- ret = unlink(path_buf);
- if (ret == -1) {
- G_warning(_("Unable to delete file '%s'"), path_buf);
- closedir(dir);
- return -1;
- }
- }
- closedir(dir);
-
- env = getenv("GRASS_VECTOR_TMPDIR_MAPSET");
- if (env && strcmp(env, "0") == 0) {
- tmp = path;
- }
- else {
- /* NFS can create .nfsxxxxxxxx files for those deleted
- * -> we have to move the directory to ./tmp before it is deleted */
- tmp = G_tempfile();
-
- G_debug(3, "rename '%s' to '%s'", path, tmp);
-
- ret = rename(path, tmp);
- if (ret == -1) {
- G_warning(_("Unable to rename directory '%s' to '%s'"), path, tmp);
- return -1;
- }
- }
- G_debug(3, "remove directory '%s'", tmp);
- /* Warning: remove() fails on Windows */
- ret = rmdir(tmp);
- if (ret == -1) {
- G_warning(_("Unable to remove directory '%s': %s"),
- tmp, strerror(errno));
- return -1;
- }
- return 0;
- }
- /*!
- \brief Set spatial index to be realease when vector is closed.
- By default, the memory occupied by spatial index is not released.
- \param Map vector map
- */
- void Vect_set_release_support(struct Map_info *Map)
- {
- Map->plus.release_support = TRUE;
- }
- /*!
- \brief Set category index to be updated when vector is changed.
- By default, category index is not updated if vector is changed,
- this function sets category index update.
- WARNING: currently only category for elements is updated not for
- areas
- \param Map vector map
- */
- void Vect_set_category_index_update(struct Map_info *Map)
- {
- Map->plus.update_cidx = TRUE;
- }
|