fs_fdopen.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /****************************************************************************
  2. * fs/vfs/fs_fdopen.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <fcntl.h>
  27. #include <errno.h>
  28. #include <nuttx/kmalloc.h>
  29. #include <nuttx/semaphore.h>
  30. #include <nuttx/fs/fs.h>
  31. #include <nuttx/lib/lib.h>
  32. #include <nuttx/net/net.h>
  33. #include "inode/inode.h"
  34. /****************************************************************************
  35. * Private Functions
  36. ****************************************************************************/
  37. /****************************************************************************
  38. * Name: fs_checkfd
  39. *
  40. * Description:
  41. * Check if the file descriptor is valid for the provided TCB and if it
  42. * supports the requested access.
  43. *
  44. ****************************************************************************/
  45. static inline int fs_checkfd(FAR struct tcb_s *tcb, int fd, int oflags)
  46. {
  47. FAR struct file *filep;
  48. FAR struct inode *inode;
  49. int ret;
  50. DEBUGASSERT(tcb && tcb->group);
  51. /* Get the file structure corresponding to the file descriptor. */
  52. ret = fs_getfilep(fd, &filep);
  53. if (ret < 0)
  54. {
  55. return ret;
  56. }
  57. /* Get the inode associated with the file descriptor. This should
  58. * normally be the case if fd >= 0. But not in the case where the
  59. * called attempts to explicitly stdin with fdopen(0) but stdin has
  60. * been closed.
  61. */
  62. inode = filep->f_inode;
  63. if (!inode)
  64. {
  65. /* No inode -- descriptor does not correspond to an open file */
  66. return -ENOENT;
  67. }
  68. /* Make sure that the inode supports the requested access. In
  69. * the case of fdopen, we are not actually creating the file -- in
  70. * particular w and w+ do not truncate the file and any files have
  71. * already been created.
  72. */
  73. if (inode_checkflags(inode, oflags) != OK)
  74. {
  75. /* Cannot support the requested access */
  76. return -EACCES;
  77. }
  78. /* Looks good to me */
  79. return OK;
  80. }
  81. /****************************************************************************
  82. * Public Functions
  83. ****************************************************************************/
  84. /****************************************************************************
  85. * Name: fs_fdopen
  86. *
  87. * Description:
  88. * This function does the core operations for fopen and fdopen.
  89. *
  90. ****************************************************************************/
  91. int fs_fdopen(int fd, int oflags, FAR struct tcb_s *tcb,
  92. FAR struct file_struct **filep)
  93. {
  94. FAR struct streamlist *slist;
  95. FAR FILE *stream;
  96. int ret;
  97. /* Check input parameters */
  98. if (fd < 0)
  99. {
  100. ret = -EBADF;
  101. goto errout;
  102. }
  103. /* A NULL TCB pointer means to use this threads TCB. This is a little
  104. * hack the let's this function be called from user-space (via a syscall)
  105. * without having access to the TCB.
  106. */
  107. if (!tcb)
  108. {
  109. tcb = nxsched_self();
  110. }
  111. DEBUGASSERT(tcb && tcb->group);
  112. /* Verify that this is a valid file/socket descriptor and that the
  113. * requested access can be support.
  114. *
  115. * Is this fd in the range of valid file descriptors? Socket descriptors
  116. * lie in a different range.
  117. */
  118. if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
  119. {
  120. /* No.. If networking is enabled then this might be a socket
  121. * descriptor.
  122. */
  123. #ifdef CONFIG_NET
  124. ret = net_checksd(fd, oflags);
  125. #else
  126. /* No networking... it is just a bad descriptor */
  127. ret = -EBADF;
  128. goto errout;
  129. #endif
  130. }
  131. /* The descriptor is in a valid range to file descriptor... perform some
  132. * more checks.
  133. */
  134. else
  135. {
  136. ret = fs_checkfd(tcb, fd, oflags);
  137. }
  138. /* Do we have a good descriptor of some sort? */
  139. if (ret < 0)
  140. {
  141. /* No... return the reported error */
  142. goto errout;
  143. }
  144. /* Get the stream list from the TCB */
  145. #ifdef CONFIG_MM_KERNEL_HEAP
  146. slist = tcb->group->tg_streamlist;
  147. #else
  148. slist = &tcb->group->tg_streamlist;
  149. #endif
  150. /* Allocate FILE structure */
  151. if (fd >= 3)
  152. {
  153. stream = group_zalloc(tcb->group, sizeof(FILE));
  154. if (stream == NULL)
  155. {
  156. ret = -ENOMEM;
  157. goto errout;
  158. }
  159. /* Add FILE structure to the stream list */
  160. ret = nxsem_wait(&slist->sl_sem);
  161. if (ret < 0)
  162. {
  163. group_free(tcb->group, stream);
  164. goto errout;
  165. }
  166. if (slist->sl_tail)
  167. {
  168. slist->sl_tail->fs_next = stream;
  169. slist->sl_tail = stream;
  170. }
  171. else
  172. {
  173. slist->sl_head = stream;
  174. slist->sl_tail = stream;
  175. }
  176. nxsem_post(&slist->sl_sem);
  177. /* Initialize the semaphore the manages access to the buffer */
  178. lib_sem_initialize(stream);
  179. }
  180. else
  181. {
  182. stream = &slist->sl_std[fd];
  183. }
  184. #ifndef CONFIG_STDIO_DISABLE_BUFFERING
  185. #if CONFIG_STDIO_BUFFER_SIZE > 0
  186. /* Set up pointers */
  187. stream->fs_bufstart = stream->fs_buffer;
  188. stream->fs_bufend = &stream->fs_bufstart[CONFIG_STDIO_BUFFER_SIZE];
  189. stream->fs_bufpos = stream->fs_bufstart;
  190. stream->fs_bufread = stream->fs_bufstart;
  191. stream->fs_flags = __FS_FLAG_UBF; /* Fake setvbuf and fclose */
  192. #ifdef CONFIG_STDIO_LINEBUFFER
  193. /* Setup buffer flags */
  194. stream->fs_flags |= __FS_FLAG_LBF; /* Line buffering */
  195. #endif /* CONFIG_STDIO_LINEBUFFER */
  196. #endif /* CONFIG_STDIO_BUFFER_SIZE > 0 */
  197. #endif /* CONFIG_STDIO_DISABLE_BUFFERING */
  198. /* Save the file description and open flags. Setting the
  199. * file descriptor locks this stream.
  200. */
  201. stream->fs_fd = fd;
  202. stream->fs_oflags = oflags;
  203. if (filep != NULL)
  204. {
  205. *filep = stream;
  206. }
  207. return OK;
  208. errout:
  209. if (filep != NULL)
  210. {
  211. *filep = NULL;
  212. }
  213. return ret;
  214. }