fs_files.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /****************************************************************************
  2. * fs/inode/fs_files.c
  3. *
  4. * Copyright (C) 2007-2009, 2011-2013, 2016 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <string.h>
  41. #include <semaphore.h>
  42. #include <assert.h>
  43. #include <sched.h>
  44. #include <errno.h>
  45. #include <nuttx/fs/fs.h>
  46. #include <nuttx/kmalloc.h>
  47. #include "inode/inode.h"
  48. /****************************************************************************
  49. * Private Functions
  50. ****************************************************************************/
  51. /****************************************************************************
  52. * Name: _files_semtake
  53. ****************************************************************************/
  54. static void _files_semtake(FAR struct filelist *list)
  55. {
  56. /* Take the semaphore (perhaps waiting) */
  57. while (sem_wait(&list->fl_sem) != 0)
  58. {
  59. /* The only case that an error should occur here is if
  60. * the wait was awakened by a signal.
  61. */
  62. ASSERT(get_errno() == EINTR);
  63. }
  64. }
  65. /****************************************************************************
  66. * Name: _files_semgive
  67. ****************************************************************************/
  68. #define _files_semgive(list) sem_post(&list->fl_sem)
  69. /****************************************************************************
  70. * Name: _files_close
  71. *
  72. * Description:
  73. * Close an inode (if open)
  74. *
  75. * Assumuptions:
  76. * Caller holds the list semaphore because the file descriptor will be freed.
  77. *
  78. ****************************************************************************/
  79. static int _files_close(FAR struct file *filep)
  80. {
  81. struct inode *inode = filep->f_inode;
  82. int ret = OK;
  83. /* Check if the struct file is open (i.e., assigned an inode) */
  84. if (inode)
  85. {
  86. /* Close the file, driver, or mountpoint. */
  87. if (inode->u.i_ops && inode->u.i_ops->close)
  88. {
  89. /* Perform the close operation */
  90. ret = inode->u.i_ops->close(filep);
  91. }
  92. /* And release the inode */
  93. inode_release(inode);
  94. /* Release the file descriptor */
  95. filep->f_oflags = 0;
  96. filep->f_pos = 0;
  97. filep->f_inode = NULL;
  98. }
  99. return ret;
  100. }
  101. /****************************************************************************
  102. * Public Functions
  103. ****************************************************************************/
  104. /****************************************************************************
  105. * Name: files_initialize
  106. *
  107. * Description:
  108. * This is called from the FS initialization logic to configure the files.
  109. *
  110. ****************************************************************************/
  111. void files_initialize(void)
  112. {
  113. }
  114. /****************************************************************************
  115. * Name: files_initlist
  116. *
  117. * Description: Initializes the list of files for a new task
  118. *
  119. ****************************************************************************/
  120. void files_initlist(FAR struct filelist *list)
  121. {
  122. DEBUGASSERT(list);
  123. /* Initialize the list access mutex */
  124. (void)sem_init(&list->fl_sem, 0, 1);
  125. }
  126. /****************************************************************************
  127. * Name: files_releaselist
  128. *
  129. * Description:
  130. * Release a reference to the file list
  131. *
  132. ****************************************************************************/
  133. void files_releaselist(FAR struct filelist *list)
  134. {
  135. int i;
  136. DEBUGASSERT(list);
  137. /* Close each file descriptor .. Normally, you would need take the list
  138. * semaphore, but it is safe to ignore the semaphore in this context because
  139. * there should not be any references in this context.
  140. */
  141. for (i = 0; i < CONFIG_NFILE_DESCRIPTORS; i++)
  142. {
  143. (void)_files_close(&list->fl_files[i]);
  144. }
  145. /* Destroy the semaphore */
  146. (void)sem_destroy(&list->fl_sem);
  147. }
  148. /****************************************************************************
  149. * Name: file_dup2
  150. *
  151. * Description:
  152. * Assign an inode to a specific files structure. This is the heart of
  153. * dup2.
  154. *
  155. ****************************************************************************/
  156. int file_dup2(FAR struct file *filep1, FAR struct file *filep2)
  157. {
  158. FAR struct filelist *list;
  159. FAR struct inode *inode;
  160. int errcode;
  161. int ret;
  162. if (!filep1 || !filep1->f_inode || !filep2)
  163. {
  164. errcode = EBADF;
  165. goto errout;
  166. }
  167. list = sched_getfiles();
  168. /* The file list can be NULL under two cases: (1) One is an obscure
  169. * cornercase: When memory management debug output is enabled. Then
  170. * there may be attempts to write to stdout from malloc before the group
  171. * data has been allocated. The other other is (2) if this is a kernel
  172. * thread. Kernel threads have no allocated file descriptors.
  173. */
  174. if (list != NULL)
  175. {
  176. _files_semtake(list);
  177. }
  178. /* If there is already an inode contained in the new file structure,
  179. * close the file and release the inode.
  180. */
  181. ret = _files_close(filep2);
  182. if (ret < 0)
  183. {
  184. /* An error occurred while closing the driver */
  185. goto errout_with_ret;
  186. }
  187. /* Increment the reference count on the contained inode */
  188. inode = filep1->f_inode;
  189. inode_addref(inode);
  190. /* Then clone the file structure */
  191. filep2->f_oflags = filep1->f_oflags;
  192. filep2->f_pos = filep1->f_pos;
  193. filep2->f_inode = inode;
  194. /* Call the open method on the file, driver, mountpoint so that it
  195. * can maintain the correct open counts.
  196. */
  197. if (inode->u.i_ops && inode->u.i_ops->open)
  198. {
  199. #ifndef CONFIG_DISABLE_MOUNTPOINT
  200. if (INODE_IS_MOUNTPT(inode))
  201. {
  202. /* Dup the open file on the in the new file structure */
  203. ret = inode->u.i_mops->dup(filep1, filep2);
  204. }
  205. else
  206. #endif
  207. {
  208. /* (Re-)open the pseudo file or device driver */
  209. ret = inode->u.i_ops->open(filep2);
  210. }
  211. /* Handle open failures */
  212. if (ret < 0)
  213. {
  214. goto errout_with_inode;
  215. }
  216. }
  217. if (list != NULL)
  218. {
  219. _files_semgive(list);
  220. }
  221. return OK;
  222. /* Handler various error conditions */
  223. errout_with_inode:
  224. inode_release(filep2->f_inode);
  225. filep2->f_oflags = 0;
  226. filep2->f_pos = 0;
  227. filep2->f_inode = NULL;
  228. errout_with_ret:
  229. errcode = -ret;
  230. if (list != NULL)
  231. {
  232. _files_semgive(list);
  233. }
  234. errout:
  235. set_errno(errcode);
  236. return ERROR;
  237. }
  238. /****************************************************************************
  239. * Name: files_allocate
  240. *
  241. * Description:
  242. * Allocate a struct files instance and associate it with an inode instance.
  243. * Returns the file descriptor == index into the files array.
  244. *
  245. ****************************************************************************/
  246. int files_allocate(FAR struct inode *inode, int oflags, off_t pos, int minfd)
  247. {
  248. FAR struct filelist *list;
  249. int i;
  250. /* Get the file descriptor list. It should not be NULL in this context. */
  251. list = sched_getfiles();
  252. DEBUGASSERT(list != NULL);
  253. _files_semtake(list);
  254. for (i = minfd; i < CONFIG_NFILE_DESCRIPTORS; i++)
  255. {
  256. if (!list->fl_files[i].f_inode)
  257. {
  258. list->fl_files[i].f_oflags = oflags;
  259. list->fl_files[i].f_pos = pos;
  260. list->fl_files[i].f_inode = inode;
  261. list->fl_files[i].f_priv = NULL;
  262. _files_semgive(list);
  263. return i;
  264. }
  265. }
  266. _files_semgive(list);
  267. return ERROR;
  268. }
  269. /****************************************************************************
  270. * Name: files_close
  271. *
  272. * Description:
  273. * Close an inode (if open)
  274. *
  275. * Assumuptions:
  276. * Caller holds the list semaphore because the file descriptor will be freed.
  277. *
  278. ****************************************************************************/
  279. int files_close(int fd)
  280. {
  281. FAR struct filelist *list;
  282. int ret;
  283. /* Get the thread-specific file list. It should never be NULL in this
  284. * context.
  285. */
  286. list = sched_getfiles();
  287. DEBUGASSERT(list != NULL);
  288. /* If the file was properly opened, there should be an inode assigned */
  289. if (fd < 0 || fd >= CONFIG_NFILE_DESCRIPTORS || !list->fl_files[fd].f_inode)
  290. {
  291. return -EBADF;
  292. }
  293. /* Perform the protected close operation */
  294. _files_semtake(list);
  295. ret = _files_close(&list->fl_files[fd]);
  296. _files_semgive(list);
  297. return ret;
  298. }
  299. /****************************************************************************
  300. * Name: files_release
  301. *
  302. * Assumuptions:
  303. * Similar to files_close(). Called only from open() logic on error
  304. * conditions.
  305. *
  306. ****************************************************************************/
  307. void files_release(int fd)
  308. {
  309. FAR struct filelist *list;
  310. list = sched_getfiles();
  311. DEBUGASSERT(list);
  312. if (fd >= 0 && fd < CONFIG_NFILE_DESCRIPTORS)
  313. {
  314. _files_semtake(list);
  315. list->fl_files[fd].f_oflags = 0;
  316. list->fl_files[fd].f_pos = 0;
  317. list->fl_files[fd].f_inode = NULL;
  318. _files_semgive(list);
  319. }
  320. }