[GRASS-dev] G_tempfile() proposed changes [relevant to creating a new location]

Paul Kelly paul-grass at stjohnspoint.co.uk
Sat Jan 6 09:57:10 EST 2007


I've had the attached changes (to G_tempfile(), g.tempfile and a couple of 
other places) sitting around for a while, but Michael's comment about 
changes to g.proj being forthcoming reminded me to hurry up and put them 
forward for discussion. The changes amount to:
  * Re-naming the current G_tempfile() to G_tempfile_in_mapset().
  * Change the calls to G_tempfile() in lib/gis/opencell.c to use the new 
function G_tempfile_in_mapset()
  * Write a new G_tempfile() that puts a tempfile in the directory pointed 
to by the TEMP environment variable if it exists (this will be somewhere 
writeable by the user on Windows) or P_tmpdir otherwise (/tmp on Unix or 
root of current drive on Windows).
  * Add a new command-line flag to g.tempfile to allow it to create a 
tempfile in the current mapset if necessary.
  * Change r.in.aster (as an example) to use g.tempfile in this way. There 
would be more examples I'm sure we could find that want to create a large 
tempfile somewhere there's more than likely to be enough space - the 
original purpose of G_tempfile, according to comments in the source. 
Although perhaps that's not all that relevant. Perhaps in the past /tmp 
might have been likely to be very small?

The reason I haven't applied the changes yet is that I'm slightly worried 
about what the effect might be of the sudden change. In particular, that 
tempfiles created by the current G_tempfile (i.e. in the current mapset) 
get cleaned up at the end of the session and after the change they won't. 
Should we just change it and fix things on a case-by-case basis? (Either 
change them to create the tempfile in the mapset, or force them to delete 
it?) A bit of a dilemma.

Paul
-------------- next part --------------
Index: general/g.tempfile/description.html
===================================================================
RCS file: /home/grass/grassrepository/grass6/general/g.tempfile/description.html,v
retrieving revision 1.2
diff -u -r1.2 description.html
--- general/g.tempfile/description.html	7 Dec 2005 13:31:15 -0000	1.2
+++ general/g.tempfile/description.html	3 Jan 2007 21:36:12 -0000
@@ -1,12 +1,19 @@
 <H2>DESCRIPTION</H2>
 
+<p>
 <EM>g.tempfile</EM>
 is designed for shell scripts that need to use large temporary files. 
 GRASS provides a mechanism for temporary files that does not depend on 
-/tmp. GRASS temporary files are created in the data base with the assumption 
+the system temporary directory (e.g. /tmp on Unix). When the -m flag is
+specified, g.tempfile creates a file in the data base with the assumption 
 that there will be enough space under the data base for large files. 
 GRASS periodically removes temporary files that have been left behind 
-by programs that failed to remove them before terminating. 
+by programs that failed to remove them before terminating.
+</p>
+<p>
+When the -m flag is not specified, the temporary filename given is located
+in the normal system temporary directory. This tends to be more suitable for
+smaller files.</p>
 
 <P>
 
@@ -33,16 +40,20 @@
 
 <H2>NOTES</H2>
 
+<p>
 Each call to <EM>g.tempfile</EM>
 creates a different (i.e. unique) name. 
-
-Although GRASS does eventually get around to removing
-tempfiles that have been left behind, the programmer should
+</p>
+<p>
+Although GRASS does remove tempfiles that have been left behind
+at the start and finish of every session, the programmer should
 make every effort to remove these files. They often get
 large and take up disk space. If you write /bin/sh scripts,
 learn to use the /bin/sh <EM>trap</EM> command. If you
 write /bin/csh scripts, learn to use the /bin/csh
-<EM>onintr</EM> command.
+<EM>onintr</EM> command. This is especially important if the -m flag
+is not used, as the temporary files will not then be deleted by GRASS.
+</p>
 
 <H2>AUTHOR</H2>
 
Index: general/g.tempfile/main.c
===================================================================
RCS file: /home/grass/grassrepository/grass6/general/g.tempfile/main.c,v
retrieving revision 2.3
diff -u -r2.3 main.c
--- general/g.tempfile/main.c	19 Aug 2006 12:52:20 -0000	2.3
+++ general/g.tempfile/main.c	3 Jan 2007 21:36:12 -0000
@@ -10,6 +10,7 @@
 {
     struct GModule *module;
     struct Option *pid;
+    struct Flag *mapset;
     char *tempfile, *G__tempfile();
     int p;
 
@@ -27,6 +28,11 @@
     pid->required = YES;
     pid->description = "Process id to use when naming the tempfile";
 
+    mapset = G_define_flag();
+    mapset->key = 'm';
+    mapset->description = "Create tempfile in current mapset (will be"
+                          "automatically deleted on exiting GRASS session)";
+     
     G_disable_interactive();
     if (G_parser(argc,argv)) exit(1);
 
@@ -35,7 +41,10 @@
 	G_usage();
 	exit(1);
     }
-    tempfile = G__tempfile(p);
+    if (mapset->answer)
+        tempfile = G__tempfile_in_mapset(p);
+    else
+        tempfile = G__tempfile(p);
     umask(0);
 /* create tempfile so next run of this program will create a unique name */
     close(creat(tempfile,0666));
Index: include/gisdefs.h
===================================================================
RCS file: /home/grass/grassrepository/grass6/include/gisdefs.h,v
retrieving revision 1.76
diff -u -r1.76 gisdefs.h
--- include/gisdefs.h	20 Dec 2006 19:10:36 -0000	1.76
+++ include/gisdefs.h	3 Jan 2007 21:36:18 -0000
@@ -1107,7 +1107,9 @@
 
 /* tempfile.c */
 char *G_tempfile(void);
+char *G_tempfile_in_mapset(void);
 char *G__tempfile(int);
+char *G__tempfile_in_mapset(int);
 int G__temp_element(char *);
 
 /* timestamp.c */
Index: lib/gis/opencell.c
===================================================================
RCS file: /home/grass/grassrepository/grass6/lib/gis/opencell.c,v
retrieving revision 2.8
diff -u -r2.8 opencell.c
--- lib/gis/opencell.c	13 Dec 2006 14:21:36 -0000	2.8
+++ lib/gis/opencell.c	3 Jan 2007 21:36:25 -0000
@@ -627,7 +627,7 @@
     G__init_window();
 
 /* open a tempfile name */
-    tempname = G_tempfile ();
+    tempname = G_tempfile_in_mapset ();
     fd = creat (tempname, 0666);
     if (fd < 0)
     {   
@@ -731,7 +731,7 @@
     fcb->cur_row = 0;
 
 /* open a null tempfile name */
-    tempname = G_tempfile ();
+    tempname = G_tempfile_in_mapset ();
     null_fd = creat (tempname, 0666);
     if (null_fd < 0)
     {   
Index: lib/gis/tempfile.c
===================================================================
RCS file: /home/grass/grassrepository/grass6/lib/gis/tempfile.c,v
retrieving revision 2.4
diff -u -r2.4 tempfile.c
--- lib/gis/tempfile.c	18 Dec 2006 08:09:36 -0000	2.4
+++ lib/gis/tempfile.c	3 Jan 2007 21:36:26 -0000
@@ -11,36 +11,62 @@
  * \date 1999-2006
  */
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <grass/gis.h>
 
-
-/**
- * \fn char *G_tempfile (void)
+/*!
+ * \brief returns a temporary file name on the same disk as the current mapset
  *
- * \brief Returns a temporary file name.
+ * This function returns a pointer to a string containing a unique file name 
+ * that can be used as a temporary file within the module. Successive calls 
+ * to the function will generate new names.
+ * 
+ * Only the file name is generated. The file itself is not created. To create the
+ * file, the module must use standard UNIX functions which create and open files,
+ * e.g., creat() or fopen(). The filename is guaranteed to be on the same disk
+ * as the current mapset. This means that "draft" output maps can
+ * be moved (with either link()+remove() or rename()) into their final
+ * location upon closure.
+ * 
+ * The programmer should take reasonable care to remove (unlink) the file 
+ * before the module exits. However, GRASS database management will 
+ * eventually remove all temporary files created by G_tempfile_in_mapset() 
+ * that have been left behind by the modules which created them.
+ *
+ *  \return char:  pointer to a character string containing the name.
+ *   the name is copied to allocated memory and may be
+ *   released by the unix free () routine.
+ */
+
+char *G_tempfile_in_mapset(void)
+{
+    return G__tempfile_in_mapset(getpid());
+}
+
+/*!
+ * \brief returns a temporary file name
  *
- * This routine returns a pointer to a string containing a unique 
- * temporary file name that can be used as a temporary file within the 
- * module. Successive calls to <i>G_tempfile()</i> will generate new 
- * names. Only the file name is generated. The file itself is not 
- * created. To create the file, the module must use standard UNIX 
- * functions which create and open files, e.g., <i>creat()</i> or 
- * <i>fopen()</i>.<br>
- *
- * Successive calls will generate different names the names are of the 
- * form pid.n where pid is the programs process id number and n is a 
- * unique identifier.<br>
- *
- * <b>Note:</b> It is recommended to <i>unlink()</i> (remove) the 
- * temp file on exit/error. Only if GRASS is left with 'exit', the GIS 
- * mapset manangement will clean up the temp directory (ETC/clean_temp).
- *
- * \return pointer to a character string containing the name. The name 
- * is copied to allocated memory and may be released by the unix free() 
- * routine.
+ * This function returns a pointer to a string containing a unique file name 
+ * that can be used as a temporary file within the module. Successive calls 
+ * to the function will generate new names.
+ * 
+ * Only the file name is generated. The file itself is not created. To create the
+ * file, the module must use standard UNIX functions which create and open files,
+ * e.g., creat() or fopen().
+ * 
+ * The programmer should take care to remove (unlink) the file before
+ * the module exits. If a module requires not to immediately delete a 
+ * temporary file and instead have it automatically deleted at the end of
+ * the GRASS session, G_tempfile_in_mapset() should be used instead.
+ *
+ *  \return char:  pointer to a character string containing the name.
+ *   the name is copied to allocated memory and may be
+ *   released by the unix free () routine.
  */
 
 char *G_tempfile(void)
@@ -48,10 +74,7 @@
     return G__tempfile(getpid());
 }
 
-
 /**
- * \fn char *G__tempfile (int pid)
- *
  * \brief Create tempfile from process id.
  *
  * See <i>G_tempfile()</i>.
@@ -62,6 +85,60 @@
 
 char *G__tempfile (int pid)
 {
+    char *env_temp = getenv("TEMP");
+    char *prefix, *path = NULL;
+    char dirsep_char[2];       
+    static int uniq = 0;
+    struct stat st;
+   
+    if (pid <= 0)
+	pid = getpid();
+   
+    if (env_temp != NULL)
+	/* This should be somewhere in user profile directory on Windows, 
+	 * thus ensuring write permission */
+        prefix = G_store(env_temp);
+    else
+        /* Usually /tmp on Unix or root of current drive on Windows */
+        prefix = G_store(P_tmpdir);
+
+    /* Often there's no harm in having an extra directory separator character
+     * in the middle of a path but just being careful here. */
+    if (G_is_dirsep( prefix[strlen(prefix)-1] )) {	       
+	dirsep_char[0] = '\0';
+    }	    
+    else {	       
+	dirsep_char[0] = GRASS_DIRSEP;
+	dirsep_char[1] = '\0';
+    }
+	    
+    do {
+        if (path != NULL)
+	    G_free(path);
+        path = G_malloc(strlen(prefix) + 40 );
+        sprintf(path, "%s%sgrass-%d.%d", prefix, dirsep_char, pid, uniq++);
+        /* We use '/'-style dirseps within GRASS */
+        G_convert_dirseps_from_host( path );
+    } while (stat(path, &st) == 0);
+
+    G_free(prefix);
+   
+    return path;
+   
+}
+
+
+/**
+ * \brief Create tempfile in current mapset from process id.
+ *
+ * See <i>G_tempfile_in_mapset()</i>.
+ *
+ * \param[in] pid
+ * \return Pointer to string path
+ */
+
+char *G__tempfile_in_mapset (int pid)
+{
     char path[1024];
     char name[GNAME_MAX];
     char element[100];
@@ -78,13 +155,14 @@
     }
     while (stat(path, &st) == 0) ;
 
+    /* We use '/'-style dirseps within GRASS */
+    G_convert_dirseps_from_host (path);
+   
     return G_store (path);
 }
 
 
 /**
- * \fn int G__temp_element (char *element)
- *
  * \brief Populates <b>element</b> with a path string.
  *
  * \param[in,out] element
Index: scripts/r.in.aster/r.in.aster
===================================================================
RCS file: /home/grass/grassrepository/grass6/scripts/r.in.aster/r.in.aster,v
retrieving revision 1.5
diff -u -r1.5 r.in.aster
--- scripts/r.in.aster/r.in.aster	19 Aug 2006 12:52:24 -0000	1.5
+++ scripts/r.in.aster/r.in.aster	3 Jan 2007 21:36:39 -0000
@@ -138,7 +138,7 @@
 	srcfile=$GIS_OPT_INPUT
 fi
 
-tempfile=`g.tempfile $$`.tif
+tempfile=`g.tempfile -m $$`.tif
 
 #run gdalwarp with selected options (must be in $PATH)
 #to translate aster image to geotiff


More information about the grass-dev mailing list