fs_files.c 11 KB

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