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