GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
mkstemp.c
Go to the documentation of this file.
1 /*!
2  * \file lib/gis/mkstemp.c
3  *
4  * \brief GIS Library - Temporary file functions.
5  *
6  * (C) 2014 by the GRASS Development Team
7  *
8  * This program is free software under the GNU General Public License
9  * (>=v2). Read the file COPYING that comes with GRASS for details.
10  *
11  * \author Glynn Clements
12  */
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <grass/gis.h>
20 #include <grass/glocale.h>
21 
22 #define MAX_REPLACE 5
23 
24 static int next(char **replace, int num_replace)
25 {
26  int i;
27 
28  for (i = 0; i < num_replace; i++) {
29  char *p = replace[i];
30  if (*p < 'z') {
31  (*p)++;
32  return 1;
33  }
34  else
35  *p = 'a';
36  }
37 
38  return 0;
39 }
40 
41 static int G__mkstemp(char *template, int flags, int mode)
42 {
43  char *replace[MAX_REPLACE];
44  int num_replace = 0;
45  char *ptr = template;
46  int fd;
47 
48  while (num_replace < MAX_REPLACE) {
49  char *p = strchr(ptr, 'X');
50  if (!p)
51  break;
52  replace[num_replace++] = p;
53  *p = 'a';
54  ptr = p + 1;
55  }
56 
57  if (!num_replace)
58  return -1;
59 
60  for (;;) {
61  if (!next(replace, num_replace))
62  return -1;
63 
64  if (access(template, F_OK) == 0)
65  continue;
66 
67  if (!flags)
68  return 0;
69 
70  fd = open(template, flags, mode);
71  if (fd < 0) {
72  if (errno == EEXIST)
73  continue;
74  return -1;
75  }
76 
77  return fd;
78  }
79 
80  return -1;
81 }
82 
83 
84 /*!
85  * \brief Opens a temporary file.
86  *
87  * This routine opens the file.
88  *
89  * The last two take the arguments "flags" and "mode". "flags" should be
90  * O_WRONLY or O_RDWR, plus any other desired flags (e.g. O_APPEND).
91  * "mode" is the file mode (0666 would be typical).
92  *
93  * The functions does not use the PID, although the caller can do so.
94  *
95  * In theory, up to 26^5 (= ~12 million) filenames will be attempted
96  * until it finds one which doesn't exist.
97  *
98  * <b>Note:</b> <i>G_mktemp()</i> as such it is prone to race
99  * conditions (some other process may create that file after G_mktemp()
100  * returns).
101  *
102  * \return file name
103  */
104 char *G_mktemp(char *template)
105 {
106  return G__mkstemp(template, 0, 0) < 0 ? NULL : template;
107 }
108 
109 /*!
110  * \brief Returns a file descriptor.
111  *
112  * This routine opens the file and returns a descriptor.
113  *
114  * The last two take the arguments "flags" and "mode". "flags" should be
115  * O_WRONLY or O_RDWR, plus any other desired flags (e.g. O_APPEND).
116  * "mode" is the file mode (0666 would be typical).
117  *
118  * The functions does not use the PID, although the caller can do so.
119  *
120  * In theory, up to 26^5 (= ~12 million) filenames will be attempted
121  * until it finds one which doesn't exist.
122  *
123  *
124  * \return file descriptor
125  */
126 
127 int G_mkstemp(char *template, int flags, int mode)
128 {
129 
130  switch (flags & O_ACCMODE) {
131  case O_RDONLY:
132  G_fatal_error(_("Attempt to create read-only temporary file"));
133  return -1;
134  case O_WRONLY:
135  case O_RDWR:
136  break;
137  default:
138  G_fatal_error(_("Unrecognised access mode: %o"), flags & O_ACCMODE);
139  return -1;
140  }
141 
142  return G__mkstemp(template, flags | O_CREAT | O_EXCL, mode);
143 }
144 
145 /*!
146  * \brief Returns a file descriptor.
147  *
148  * This routine opens the file and returns a FILE*.
149  *
150  * The last two take the arguments "flags" and "mode". "flags" should be
151  * O_WRONLY or O_RDWR, plus any other desired flags (e.g. O_APPEND).
152  * "mode" is the file mode (0666 would be typical).
153  *
154  * The functions does not use the PID, although the caller can do so.
155  *
156  * In theory, up to 26^5 (= ~12 million) filenames will be attempted
157  * until it finds one which doesn't exist.
158  *
159  * \return FILE*
160  */
161 
162 FILE *G_mkstemp_fp(char *template, int flags, int mode)
163 {
164  const char *fmode = ((flags & O_ACCMODE) == O_RDWR)
165  ? ((flags & O_APPEND) ? "a+" : "w+")
166  : ((flags & O_APPEND) ? "a" : "w");
167  int fd = G_mkstemp(template, flags, mode);
168  if (fd < 0)
169  return NULL;
170  return fdopen(fd, fmode);
171 }
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define NULL
Definition: ccmath.h:32
FILE * G_mkstemp_fp(char *template, int flags, int mode)
Returns a file descriptor.
Definition: mkstemp.c:162
int G_mkstemp(char *template, int flags, int mode)
Returns a file descriptor.
Definition: mkstemp.c:127
#define MAX_REPLACE
Definition: mkstemp.c:22
char * G_mktemp(char *template)
Opens a temporary file.
Definition: mkstemp.c:104
#define _(str)
Definition: glocale.h:10