mkstemp.c 3.7 KB

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