patacongo commented on code in PR #10602: URL: https://github.com/apache/nuttx/pull/10602#discussion_r1325337992
########## libs/libc/stdio/lib_fopencookie.c: ########## @@ -0,0 +1,229 @@ +/**************************************************************************** + * libs/libc/stdio/lib_fopencookie.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "libc.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct cookie_s +{ + void *cookie; /* pointer to the caller's cookie struct */ + cookie_io_functions_t cookie_io; /* programmer-defined hook functions */ + int cookie_fd; /* file descriptor */ +}; + +static ssize_t freadcookie(FAR struct file *filep, FAR char *buf, + size_t nbytes); +static ssize_t fwritecookie(FAR struct file *filep, FAR const char *buf, + size_t nbytes); +static off_t fseekcookie(FAR struct file *filep, off_t offset, int whence); +static int fclosecookie(FAR struct file *filep); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations cookie_fops = +{ + NULL, /* open */ + fclosecookie, /* close */ + freadcookie, /* read */ + fwritecookie, /* write */ + fseekcookie, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL, /* poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static ssize_t freadcookie(FAR struct file *filep, FAR char *buf, + size_t nbytes) +{ + struct cookie_s *cookie = (struct cookie_s *)filep->f_priv; + int ret; + + DEBUGASSERT(cookie->cookie != NULL && cookie->cookie_io.read != NULL); + + ret = cookie->cookie_io.read(cookie->cookie, buf, nbytes); + return ret; +} + +static ssize_t fwritecookie(FAR struct file *filep, FAR const char *buf, + size_t nbytes) +{ + struct cookie_s *cookie = (struct cookie_s *)filep->f_priv; + int ret; + + DEBUGASSERT(cookie->cookie != NULL && cookie->cookie_io.write != NULL); + + ret = cookie->cookie_io.write(cookie->cookie, (FAR const char *)buf, + nbytes); + return ret; +} + +static off_t fseekcookie(FAR struct file *filep, off_t offset, int whence) +{ + struct cookie_s *cookie = (struct cookie_s *)filep->f_priv; + int ret; + + DEBUGASSERT(cookie->cookie != NULL && cookie->cookie_io.seek != NULL); + + ret = cookie->cookie_io.seek(cookie->cookie, &offset, whence); + return ret; +} + +static int fclosecookie(FAR struct file *filep) +{ + struct cookie_s *cookie = (struct cookie_s *)filep->f_priv; + int ret; + + DEBUGASSERT(cookie->cookie != NULL && cookie->cookie_io.close != NULL); + + ret = cookie->cookie_io.close(cookie->cookie); + + free(filep->f_priv); + free(filep->f_inode); + close(cookie->cookie_fd); + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fopencookie + ****************************************************************************/ + +FAR FILE *fopencookie(void *restrict cookie, const char *restrict mode, + cookie_io_functions_t io_funcs) +{ + FAR FILE *filestructp = NULL; + FAR struct file filep; + FAR struct inode *inode; + FAR struct cookie_s *cookie_priv; + int oflags; + int ret; + int fd; + + /* Map the open mode string to open flags */ + + oflags = lib_mode2oflags(mode); + if (oflags < 0) + { + return NULL; + } + + /* Allocate necessary structures. */ + + inode = lib_zalloc(sizeof(struct inode)); + if (inode == NULL) + { + set_errno(-ENOMEM); + goto fopencookie_return; + } + + cookie_priv = lib_zalloc(sizeof(struct cookie_s)); + if (cookie_priv == NULL) + { + free(inode); + set_errno(-ENOMEM); + goto fopencookie_return; + } + + memset(&filep, 0, sizeof(filep)); + + /* Fill cookie_priv structure. We need to add cookie provided by user + * and functions providd by user. + */ + + cookie_priv->cookie = cookie; + cookie_priv->cookie_io.read = io_funcs.read; + cookie_priv->cookie_io.write = io_funcs.write; + cookie_priv->cookie_io.seek = io_funcs.seek; + cookie_priv->cookie_io.close = io_funcs.close; + + /* Add file operations */ + + inode->u.i_ops = &cookie_fops; + + filep.f_oflags = oflags; + filep.f_inode = inode; + filep.f_priv = cookie_priv; + + /* And get file descriptor. */ + + fd = file_allocate_from_tcb(nxsched_self(), filep.f_inode, filep.f_oflags, Review Comment: > Since stdio is a pure usespace library, I would suggest keep all fopencookie related stuff in libc to avoid the complexity of kernel/userspace interactions. That would not solve the technical problem. It eliminates the kernal/user privilege issue, but is otherwise insufficient. That is because the caller executes in Task/Process A but the user-implementation of the file is implemented in a different Task/Process B. There are lots of problems with that: - You would be executing code in Task B in the context of Task A. - That means Task B would use Task A's stack and file structures, not those of Task B. - The Task B file system code could not access Task B's TLS data . - From the standpoint of the OS, Task A is running, not Task B. Task B could not access the OS as Task B and many things just would not work properly. - The logic in Task B would run with with priority and identity of Task A. - It would not work at all in the KERNEL build mode because Task B resides in a different process address space than does Task A. That would crash immediately and dramatically. - etc. Many more issues. I don't believe that any of that behavior is acceptable. There is really no situation where can generally call from code in one task into code in another task, regardless of kernel/user privileges or of the build mode (although the problem is insurmountable in the KERNEL build mode). I still believe that the only viable solution must depend on using a proper POSIX IPC like signals, message queues, fifos, local networks, etc. Then Task B runs in the proper context and address space of Task B. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org