This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 2219ffa1e843b9f813cd4bc34197f93a625fcb8e
Author: Marco Casaroli <[email protected]>
AuthorDate: Tue Oct 20 19:32:48 2026 +0200

    libs/libc/stdlib: Add mkostemp(), mkstemps() and mkostemps().
    
    <stdlib.h> mapped mkostemp64(), mkstemps64() and mkostemps64() to
    mkostemp(), mkstemps() and mkostemps(), but libc did not have them.
    mkostemp() is in POSIX.1-2024; mkstemps() and mkostemps() are in the
    other C libraries.  A program that uses them did not link.
    
    mkostemps() replaces the X's before a suffix of suffixlen characters,
    then creates the file with O_EXCL and the extra open() flags.  The X's
    are made with mktemp(), with the suffix cut off while it runs.  If the
    file exists (another process made it in the meantime), it tries the
    next name.  mkostemp(), mkstemps() and mkstemp() call it.  So mkstemp()
    now also tries again when the file exists, instead of failing.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 include/stdlib.h               |   3 +
 libs/libc/libc.csv             |   3 +
 libs/libc/stdlib/lib_mkstemp.c | 123 +++++++++++++++++++++++++++++++++++++----
 3 files changed, 118 insertions(+), 11 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index 60de89e5af4..92ffb7a9161 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -280,6 +280,9 @@ lldiv_t   lldiv(long long number, long long denom);
 
 FAR char *mktemp(FAR char *path_template);
 int       mkstemp(FAR char *path_template);
+int       mkostemp(FAR char *path_template, int flags);
+int       mkstemps(FAR char *path_template, int suffixlen);
+int       mkostemps(FAR char *path_template, int suffixlen, int flags);
 FAR char *mkdtemp(FAR char *path_template);
 
 /* Sorting */
diff --git a/libs/libc/libc.csv b/libs/libc/libc.csv
index ad29135ee64..45c5b7d4e26 100644
--- a/libs/libc/libc.csv
+++ b/libs/libc/libc.csv
@@ -191,7 +191,10 @@
 "memset","string.h","","FAR void *","FAR void *","int","size_t"
 "mkdtemp","stdlib.h","","FAR char *","FAR char *"
 "mkfifo","sys/stat.h","defined(CONFIG_PIPES) && CONFIG_DEV_FIFO_SIZE > 
0","int","FAR const char *","mode_t"
+"mkostemp","stdlib.h","","int","FAR char *","int"
+"mkostemps","stdlib.h","","int","FAR char *","int","int"
 "mkstemp","stdlib.h","","int","FAR char *"
+"mkstemps","stdlib.h","","int","FAR char *","int"
 "mktemp","stdlib.h","","FAR char *","FAR char *"
 "mktime","time.h","","time_t","FAR struct tm *"
 "nice","unistd.h","","int","int"
diff --git a/libs/libc/stdlib/lib_mkstemp.c b/libs/libc/stdlib/lib_mkstemp.c
index 6f65bfed25d..52e05854921 100644
--- a/libs/libc/stdlib/lib_mkstemp.c
+++ b/libs/libc/stdlib/lib_mkstemp.c
@@ -27,14 +27,123 @@
 #include <nuttx/config.h>
 #include <nuttx/compiler.h>
 
-#include <unistd.h>
-#include <stdlib.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* mktemp() replaces at most six X's */
+
+#define MKSTEMP_MAXXS    6
+
+/* The number of names that are tried when the file exists */
+
+#define MKSTEMP_RETRIES  238328  /* 62**3 */
 
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: mkostemps
+ *
+ * Description:
+ *   Replace the X's (up to six) before the last suffixlen characters of
+ *   path_template with characters that make the name unique, then create
+ *   and open the file for reading and writing.  If another process created
+ *   a file of that name in the meantime, try a new name.
+ *
+ * Input Parameters:
+ *   path_template - The name of the file to create, with the X's.
+ *   suffixlen     - The number of characters after the X's.
+ *   flags         - More flags for open(), such as O_CLOEXEC or O_APPEND.
+ *
+ * Returned Value:
+ *   An open file descriptor on success.  Otherwise -1 is returned and
+ *   errno is set.
+ *
+ ****************************************************************************/
+
+int mkostemps(FAR char *path_template, int suffixlen, int flags)
+{
+  char suffix0;
+  size_t len = strlen(path_template);
+  size_t end;
+  size_t xlen;
+  int retries;
+  int fd;
+
+  if (suffixlen < 0 || (size_t)suffixlen > len)
+    {
+      set_errno(EINVAL);
+      return -1;
+    }
+
+  /* Count the X's before the suffix */
+
+  end = len - suffixlen;
+  for (xlen = 0; xlen < MKSTEMP_MAXXS && xlen < end &&
+       path_template[end - xlen - 1] == 'X'; xlen++);
+
+  for (retries = 0; retries < MKSTEMP_RETRIES; retries++)
+    {
+      /* mktemp() replaces the X's at the end of the string: cut the suffix
+       * off while it runs.
+       */
+
+      memset(&path_template[end - xlen], 'X', xlen);
+      suffix0 = path_template[end];
+      path_template[end] = '\0';
+      if (mktemp(path_template) == NULL)
+        {
+          path_template[end] = suffix0;
+          return -1;
+        }
+
+      path_template[end] = suffix0;
+
+      fd = open(path_template, O_RDWR | O_CREAT | O_EXCL |
+                (flags & ~O_ACCMODE), 0600);
+      if (fd >= 0 || get_errno() != EEXIST || xlen == 0)
+        {
+          return fd;
+        }
+    }
+
+  return -1;
+}
+
+/****************************************************************************
+ * Name: mkostemp
+ *
+ * Description:
+ *   As mkstemp(), with more flags for open().
+ *
+ ****************************************************************************/
+
+int mkostemp(FAR char *path_template, int flags)
+{
+  return mkostemps(path_template, 0, flags);
+}
+
+/****************************************************************************
+ * Name: mkstemps
+ *
+ * Description:
+ *   As mkstemp(), with suffixlen characters after the X's.
+ *
+ ****************************************************************************/
+
+int mkstemps(FAR char *path_template, int suffixlen)
+{
+  return mkostemps(path_template, suffixlen, 0);
+}
+
 /****************************************************************************
  * Name: mkstemp
  *
@@ -63,13 +172,5 @@
 
 int mkstemp(FAR char *path_template)
 {
-  FAR char *path = mktemp(path_template);
-  int ret = ERROR;
-
-  if (path)
-    {
-      ret = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
-    }
-
-  return ret;
+  return mkostemps(path_template, 0, 0);
 }

Reply via email to