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-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new fa2dd7038 system/popen: Avoid copying FILE
fa2dd7038 is described below

commit fa2dd70386be572446d2dad5bd8ed8b56431429d
Author: Nightt <[email protected]>
AuthorDate: Wed Jun 3 09:54:17 2026 +0800

    system/popen: Avoid copying FILE
    
    Use fopencookie() to attach the popen fd and shell pid to the returned FILE 
stream instead of copying FILE into the popen container.
    
    Keep the upstream dpopen()/dpclose() implementation as the process and 
descriptor backend, and make pclose() close the cookie-backed stream directly.
    
    Fixes #2937.
    
    Signed-off-by: Nightt <[email protected]>
---
 system/popen/popen.c | 104 ++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 70 insertions(+), 34 deletions(-)

diff --git a/system/popen/popen.c b/system/popen/popen.c
index 4f46e6cd2..f4fdfab94 100644
--- a/system/popen/popen.c
+++ b/system/popen/popen.c
@@ -37,17 +37,65 @@
  * Private Types
  ****************************************************************************/
 
-/* struct popen_file_s is a cast compatible version of FILE that contains
- * the additional PID of the shell processes needed by pclose().
- */
-
 struct popen_file_s
 {
-  FILE copy;
-  FILE *original;
+  int fd;
   pid_t shell;
 };
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: popen_file_read
+ ****************************************************************************/
+
+static ssize_t popen_file_read(FAR void *cookie, FAR char *buf,
+                               size_t size)
+{
+  FAR struct popen_file_s *filep = (FAR struct popen_file_s *)cookie;
+
+  return read(filep->fd, buf, size);
+}
+
+/****************************************************************************
+ * Name: popen_file_write
+ ****************************************************************************/
+
+static ssize_t popen_file_write(FAR void *cookie, FAR const char *buf,
+                                size_t size)
+{
+  FAR struct popen_file_s *filep = (FAR struct popen_file_s *)cookie;
+
+  return write(filep->fd, buf, size);
+}
+
+/****************************************************************************
+ * Name: popen_file_seek
+ ****************************************************************************/
+
+static off_t popen_file_seek(FAR void *cookie, FAR off_t *offset,
+                             int whence)
+{
+  set_errno(ESPIPE);
+  return ERROR;
+}
+
+/****************************************************************************
+ * Name: popen_file_close
+ ****************************************************************************/
+
+static int popen_file_close(FAR void *cookie)
+{
+  FAR struct popen_file_s *filep = (FAR struct popen_file_s *)cookie;
+  int ret;
+
+  ret = dpclose(filep->fd, filep->shell);
+  free(filep);
+  return ret < 0 ? ERROR : OK;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -93,6 +141,15 @@ struct popen_file_s
 FILE *popen(FAR const char *command, FAR const char *mode)
 {
   FAR struct popen_file_s *container;
+  FAR FILE *stream;
+  cookie_io_functions_t popen_io =
+    {
+      .read  = popen_file_read,
+      .write = popen_file_write,
+      .seek  = popen_file_seek,
+      .close = popen_file_close
+    };
+
   int oflag;
   int fd;
 
@@ -142,8 +199,9 @@ FILE *popen(FAR const char *command, FAR const char *mode)
 
   /* Wrap the raw fd in a FILE stream */
 
-  container->original = fdopen(fd, mode);
-  if (container->original == NULL)
+  container->fd = fd;
+  stream = fopencookie(container, mode, popen_io);
+  if (stream == NULL)
     {
       int errcode = errno;
       dpclose(fd, container->shell);
@@ -152,8 +210,7 @@ FILE *popen(FAR const char *command, FAR const char *mode)
       return NULL;
     }
 
-  memcpy(&container->copy, container->original, sizeof(FILE));
-  return &container->copy;
+  return stream;
 }
 
 /****************************************************************************
@@ -193,33 +250,12 @@ FILE *popen(FAR const char *command, FAR const char *mode)
  *   stream - The stream reference returned by a previous call to popen()
  *
  * Returned Value:
- *   The child termination status on success, or -1 (ERROR) on failure
- *   with errno set.
+ *   Zero (OK) is returned on success; otherwise -1 (ERROR) is returned and
+ *   errno is set appropriately.
  *
  ****************************************************************************/
 
 int pclose(FILE *stream)
 {
-  FAR struct popen_file_s *container = (FAR struct popen_file_s *)stream;
-  FILE *original;
-  pid_t shell;
-
-  original = container->original;
-
-  /* Set the state of the original file descriptor to the state of the
-   * working copy
-   */
-
-  memcpy(original, &container->copy, sizeof(FILE));
-
-  /* Then close the original and free the container (saving the PID of the
-   * shell process).  Pass -1 to dpclose since fclose already closed the fd.
-   */
-
-  fclose(original);
-
-  shell = container->shell;
-  free(container);
-
-  return dpclose(-1, shell);
+  return fclose(stream);
 }

Reply via email to