xref: /third_party/NuttX/fs/inode/fs_files.c (revision beacf11b)
1/****************************************************************************
2 * fs/inode/fs_files.c
3 *
4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5 * Based on NuttX originally written by Gregory Nutt
6 *
7 *   Copyright (C) 2007-2009, 2011-2013, 2016-2017 Gregory Nutt. All rights
8 *     reserved.
9 *   Author: Gregory Nutt <gnutt@nuttx.org>
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in
19 *    the documentation and/or other materials provided with the
20 *    distribution.
21 * 3. Neither the name NuttX nor the names of its contributors may be
22 *    used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
32 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
33 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 ****************************************************************************/
39
40/****************************************************************************
41 * Included Files
42 ****************************************************************************/
43#include "unistd.h"
44#include "vfs_config.h"
45#include "sys/types.h"
46#include "string.h"
47#include "dirent.h"
48#include "semaphore.h"
49#include "assert.h"
50#include "errno.h"
51#include "fs/file.h"
52#include "stdio.h"
53#include "stdlib.h"
54#include "vnode.h"
55#include "los_mux.h"
56#include "fs/fd_table.h"
57#ifdef LOSCFG_NET_LWIP_SACK
58#include "lwip/sockets.h"
59#endif
60#include "los_process_pri.h"
61#include "los_vm_filemap.h"
62#include "mqueue.h"
63#define ferr PRINTK
64
65#if CONFIG_NFILE_DESCRIPTORS > 0
66struct filelist tg_filelist = { 0 };
67#endif
68
69/****************************************************************************
70 * Pre-processor Definitions
71 ****************************************************************************/
72
73struct filelist *sched_getfiles(void)
74{
75#if CONFIG_NFILE_DESCRIPTORS > 0
76  return &tg_filelist;
77#else
78  return NULL;
79#endif
80}
81
82/* 32: An unsigned int takes 32 bits */
83
84static unsigned int bitmap[CONFIG_NFILE_DESCRIPTORS / 32 + 1] = {0};
85
86static void set_bit(int i, void *addr)
87{
88  unsigned int tem = (unsigned int)i >> 5; /* Get the bitmap subscript */
89  unsigned int *addri = (unsigned int *)addr + tem;
90  unsigned int old = *addri;
91  old = old | (1UL << ((unsigned int)i & 0x1f)); /* set the new map bit */
92  *addri = old;
93}
94
95static void clear_bit(int i, void *addr)
96{
97  unsigned int tem = (unsigned int)i >> 5; /* Get the bitmap subscript */
98  unsigned int *addri = (unsigned int *)addr + tem;
99  unsigned int old = *addri;
100  old = old & ~(1UL << ((unsigned int)i & 0x1f)); /* Clear the old map bit */
101  *addri = old;
102}
103
104bool get_bit(int i)
105{
106  unsigned int *p = NULL;
107  unsigned int mask;
108
109  p = ((unsigned int *)bitmap) + (i >> 5); /* Gets the location in the bitmap */
110  mask = 1 << (i & 0x1f); /* Gets the mask for the current bit int bitmap */
111  if (!(~(*p) & mask)){
112    return true;
113  }
114  return false;
115}
116
117/****************************************************************************
118 * Private Functions
119 ****************************************************************************/
120
121/****************************************************************************
122 * Name: _files_semtake
123 ****************************************************************************/
124
125static void _files_semtake(struct filelist *list)
126{
127  /* Take the semaphore (perhaps waiting) */
128
129  while (sem_wait(&list->fl_sem) != 0)
130    {
131      /* The only case that an error should occur here is if the wait was
132       * awakened by a signal.
133       */
134
135      LOS_ASSERT(get_errno() == EINTR);
136    }
137}
138
139/****************************************************************************
140 * Name: _files_semgive
141 ****************************************************************************/
142
143#define _files_semgive(list)  (void)sem_post(&list->fl_sem)
144
145void file_hold(struct file *filep)
146{
147  struct filelist *list = sched_getfiles();
148  if (!list)
149    {
150      return;
151    }
152
153  _files_semtake(list);
154  if (filep != NULL)
155    {
156      assert(filep->f_refcount > 0);
157      filep->f_refcount++;
158    }
159  _files_semgive(list);
160}
161
162void file_release(struct file *filep)
163{
164  struct filelist *list = sched_getfiles();
165  if (!list)
166    {
167      return;
168    }
169
170  _files_semtake(list);
171  if (filep != NULL)
172    {
173      assert(filep->f_refcount > 0);
174      filep->f_refcount--;
175    }
176  _files_semgive(list);
177}
178
179/****************************************************************************
180 * Name: _files_close
181 *
182 * Description:
183 *   Close an vnode (if open)
184 *
185 * Assumuptions:
186 *   Caller holds the list semaphore because the file descriptor will be freed.
187 *
188 ****************************************************************************/
189
190static int _files_close(struct file *filep)
191{
192  struct Vnode *vnode = filep->f_vnode;
193  int ret = OK;
194
195  /* Check if the struct file is open (i.e., assigned an vnode) */
196  if (filep->f_oflags & O_DIRECTORY)
197    {
198      ret = closedir(filep->f_dir);
199      if (ret != OK)
200        {
201          return ret;
202        }
203    }
204  else
205    {
206      /* Close the file, driver, or mountpoint. */
207      if (filep->ops && filep->ops->close)
208        {
209          /* Perform the close operation */
210
211          ret = filep->ops->close(filep);
212          if (ret != OK)
213            {
214              return ret;
215            }
216        }
217      VnodeHold();
218      vnode->useCount--;
219      /* Block char device is removed when close */
220      if (vnode->type == VNODE_TYPE_BCHR)
221        {
222          ret = VnodeFree(vnode);
223          if (ret < 0)
224            {
225              PRINTK("Removing bchar device %s failed\n", filep->f_path);
226            }
227        }
228      VnodeDrop();
229    }
230
231  /* Release the file descriptor */
232
233  memset(filep, 0, sizeof(struct file));
234  filep->fd = -1;
235
236  return ret;
237}
238
239/****************************************************************************
240 * Public Functions
241 ****************************************************************************/
242
243/****************************************************************************
244 * Name: files_initialize
245 *
246 * Description:
247 *   This is called from the FS initialization logic to configure the files.
248 *
249 ****************************************************************************/
250
251void files_initialize(void)
252{
253}
254
255/****************************************************************************
256 * Name: files_initlist
257 *
258 * Description: Initializes the list of files for a new task
259 *
260 ****************************************************************************/
261
262void files_initlist(struct filelist *list)
263{
264  DEBUGASSERT(list);
265
266  /* Initialize the list access mutex */
267
268  (void)sem_init(&list->fl_sem, 0, 1);
269}
270
271/****************************************************************************
272 * Name: files_releaselist
273 *
274 * Description:
275 *   Release a reference to the file list
276 *
277 ****************************************************************************/
278
279void files_releaselist(struct filelist *list)
280{
281  int i;
282
283  DEBUGASSERT(list);
284
285  /* Close each file descriptor .. Normally, you would need take the list
286   * semaphore, but it is safe to ignore the semaphore in this context because
287   * there should not be any references in this context.
288   */
289
290  for (i = 0; i < CONFIG_NFILE_DESCRIPTORS; i++)
291    {
292      (void)_files_close(&list->fl_files[i]);
293    }
294
295  /* Destroy the semaphore */
296
297  (void)sem_destroy(&list->fl_sem);
298}
299
300/****************************************************************************
301 * Name: file_dup2
302 *
303 * Description:
304 *   Assign an vnode to a specific files structure.  This is the heart of
305 *   dup2.
306 *
307 *   Equivalent to the non-standard fs_dupfd2() function except that it
308 *   accepts struct file instances instead of file descriptors and it does
309 *   not set the errno variable.
310 *
311 * Returned Value:
312 *   Zero (OK) is returned on success; a negated errno value is return on
313 *   any failure.
314 *
315 ****************************************************************************/
316
317int file_dup2(struct file *filep1, struct file *filep2)
318{
319  struct filelist *list = NULL;
320  struct Vnode *vnode_ptr = NULL;
321  int err;
322  int ret;
323
324  if (!filep1 || !filep1->f_vnode || !filep2)
325    {
326      err = -EBADF;
327      goto errout;
328    }
329
330  list = sched_getfiles();
331  DEBUGASSERT(list);
332  /* The file list can be NULL under two cases:  (1) One is an obscure
333   * cornercase:  When memory management debug output is enabled.  Then
334   * there may be attempts to write to stdout from malloc before the group
335   * data has been allocated.  The other other is (2) if this is a kernel
336   * thread.  Kernel threads have no allocated file descriptors.
337   */
338
339  if (list != NULL)
340    {
341      _files_semtake(list);
342    }
343
344  /* If there is already an vnode contained in the new file structure,
345   * close the file and release the vnode.
346   */
347
348  ret = _files_close(filep2);
349  if (ret < 0)
350    {
351      /* An error occurred while closing the driver */
352
353      goto errout_with_ret;
354    }
355
356  /* Increment the reference count on the contained vnode */
357
358  vnode_ptr = filep1->f_vnode;
359
360  /* Then clone the file structure */
361
362  filep2->f_oflags = filep1->f_oflags;
363  filep2->f_pos    = filep1->f_pos;
364  filep2->f_vnode  = filep1->f_vnode;
365  filep2->f_priv   = filep1->f_priv;
366  filep2->f_path   = filep1->f_path;
367  filep2->ops      = filep1->ops;
368  filep2->f_refcount = filep1->f_refcount;
369
370  /* Call the open method on the file, driver, mountpoint so that it
371   * can maintain the correct open counts.
372   */
373  if (vnode_ptr->vop)
374    {
375      if (vnode_ptr->flag & VNODE_FLAG_MOUNT_NEW)
376        {
377            ret = -ENOSYS;
378        }
379      else
380        {
381          /* (Re-)open the pseudo file or device driver */
382
383          if (vnode_ptr->vop->Open)
384            {
385              ret = vnode_ptr->vop->Open(vnode_ptr, 0, 0, 0);
386            }
387          else
388            {
389              ret = -ENOSYS;
390            }
391        }
392
393      /* Handle open failures */
394
395      if (ret < 0)
396        {
397          goto errout_with_vnode;
398        }
399    }
400
401  if (list != NULL)
402    {
403      _files_semgive(list);
404    }
405  return OK;
406
407  /* Handle various error conditions */
408
409errout_with_vnode:
410  memset(filep2, 0, sizeof(struct file));
411  filep2->fd = -1;
412
413errout_with_ret:
414  err               = -ret;
415  _files_semgive(list);
416
417errout:
418  set_errno(err);
419  return VFS_ERROR;
420}
421
422struct file *files_allocate(const struct Vnode *vnode_ptr, int oflags, off_t pos, const void *priv, int minfd)
423{
424  struct filelist *list = NULL;
425  unsigned int *p = NULL;
426  unsigned int mask;
427  unsigned int i;
428  struct file *filep = NULL;
429
430  if (minfd < FILE_START_FD)
431    {
432      minfd = FILE_START_FD;
433    }
434  i = (unsigned int)minfd;
435
436  list = sched_getfiles();
437  DEBUGASSERT(list);
438
439  _files_semtake(list);
440
441  while (i < CONFIG_NFILE_DESCRIPTORS)
442    {
443      p = ((unsigned int *)bitmap) + (i >> 5); /* Gets the location in the bitmap */
444      mask = 1 << (i & 0x1f); /* Gets the mask for the current bit int bitmap */
445      if ((~(*p) & mask))
446        {
447          set_bit(i, bitmap);
448          filep = &list->fl_files[i];
449          filep->f_oflags   = oflags;
450          filep->f_pos      = pos;
451          filep->f_vnode    = (struct Vnode *)vnode_ptr;
452          filep->f_priv     = (void *)priv;
453          filep->f_refcount = 1;
454          filep->f_mapping  = (struct page_mapping *)&vnode_ptr->mapping;
455          filep->f_dir      = NULL;
456          filep->f_path     = vnode_ptr->filePath;
457          filep->fd         = i;
458          filep->ops        = vnode_ptr->fop;
459          _files_semgive(list);
460          return filep;
461        }
462      i++;
463    }
464
465  _files_semgive(list);
466  return NULL;
467}
468
469int files_close_internal(int fd, LosProcessCB *processCB)
470{
471  int ret = OK;
472  struct filelist *list = NULL;
473  struct files_struct *process_files = NULL;
474
475  /* 0,1,2 fd is not opened in system, no need to close them */
476  if ((fd >= STDIN_FILENO) && (fd <= STDERR_FILENO))
477    {
478      return OK;
479    }
480
481  /* Get the thread-specific file list.  It should never be NULL in this
482   * context.
483   */
484
485  list = sched_getfiles();
486  DEBUGASSERT(list != NULL);
487
488  /* If the file was properly opened, there should be an vnode assigned */
489
490  if (fd < 0 || fd >= CONFIG_NFILE_DESCRIPTORS || !list->fl_files[fd].f_vnode)
491    {
492      return -EBADF;
493    }
494
495  /* Perform the protected close operation */
496
497  _files_semtake(list);
498  process_files = processCB->files;
499  if (process_files == NULL)
500    {
501      PRINT_ERR("process files is NULL, %s %d\n", __FUNCTION__ ,__LINE__);
502      _files_semgive(list);
503      return -EINVAL;
504    }
505
506  list->fl_files[fd].f_refcount--;
507  if (list->fl_files[fd].f_refcount == 0)
508    {
509      ret = _files_close(&list->fl_files[fd]);
510      if (ret == OK)
511        {
512          clear_bit(fd, bitmap);
513        }
514    }
515
516  _files_semgive(list);
517  return ret;
518}
519
520/****************************************************************************
521 * Name: files_close
522 *
523 * Description:
524 *   Close an inode (if open)
525 *
526 * Assumuptions:
527 *   Caller holds the list semaphore because the file descriptor will be freed.
528 *
529 ****************************************************************************/
530
531int files_close(int fd)
532{
533  return files_close_internal(fd, OsCurrProcessGet());
534}
535
536/****************************************************************************
537 * Name: files_release
538 *
539 * Assumuptions:
540 *   Similar to files_close().  Called only from open() logic on error
541 *   conditions.
542 *
543 ****************************************************************************/
544
545void files_release(int fd)
546{
547  struct filelist *list = NULL;
548
549  list = sched_getfiles();
550  DEBUGASSERT(list);
551
552  if (fd >=0 && fd < CONFIG_NFILE_DESCRIPTORS)
553    {
554      _files_semtake(list);
555      struct file *filep = &list->fl_files[fd];
556
557      memset(filep, 0, sizeof(struct file));
558      filep->fd = -1;
559      clear_bit(fd, bitmap);
560      _files_semgive(list);
561    }
562}
563
564struct Vnode *files_get_openfile(int fd)
565{
566  struct filelist *list = NULL;
567  unsigned int *p = NULL;
568  unsigned int mask;
569
570  list = sched_getfiles();
571  DEBUGASSERT(list);
572
573  p = ((unsigned int *)bitmap) + ((unsigned int)fd >> 5); /* Gets the location in the bitmap */
574  mask = 1 << ((unsigned int)fd & 0x1f); /* Gets the mask for the current bit int bitmap */
575  if ((~(*p) & mask))
576    {
577      return NULL;
578    }
579
580  return list->fl_files[fd].f_vnode;
581}
582
583int alloc_fd(int minfd)
584{
585  struct filelist *list = NULL;
586  unsigned int *p = NULL;
587  unsigned int mask;
588  unsigned int i;
589
590  /* minfd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
591
592  if (minfd < FILE_START_FD)
593    {
594      minfd = FILE_START_FD;
595    }
596  i = (unsigned int)minfd;
597
598  list = sched_getfiles();
599  DEBUGASSERT(list);
600
601  _files_semtake(list);
602
603  while (i < CONFIG_NFILE_DESCRIPTORS)
604    {
605      p = ((unsigned int *)bitmap) + (i >> 5); /* Gets the location in the bitmap */
606      mask = 1 << (i & 0x1f); /* Gets the mask for the current bit int bitmap */
607      if ((~(*p) & mask))
608        {
609          set_bit(i, bitmap);
610          _files_semgive(list);
611          return (int)i;
612        }
613      i++;
614    }
615  _files_semgive(list);
616  return VFS_ERROR;
617}
618
619void clear_fd(int fd)
620{
621  clear_bit(fd, bitmap);
622}
623
624int close_files(struct Vnode *vnode)
625{
626  int fd = 0;
627  int ret = 0;
628  struct Vnode *open_file_vnode = NULL;
629
630  for (fd = FILE_START_FD; fd < CONFIG_NFILE_DESCRIPTORS; fd++)
631    {
632      open_file_vnode = files_get_openfile(fd);
633      if (open_file_vnode && (open_file_vnode == vnode))
634        {
635          ret = files_close(fd);
636          if (ret < 0)
637            {
638              return -EBUSY;
639            }
640        }
641    }
642
643  return 0;
644}
645
646void files_refer(int fd)
647{
648  struct file *filep = NULL;
649
650  struct filelist *list = sched_getfiles();
651  if (!list || fd < 0 || fd >= CONFIG_NFILE_DESCRIPTORS)
652    {
653      return;
654    }
655
656  _files_semtake(list);
657  (void)fs_getfilep(fd, &filep);
658  if (filep != NULL)
659    {
660      filep->f_refcount++;
661    }
662  _files_semgive(list);
663}
664
665void alloc_std_fd(struct fd_table_s *fdt)
666{
667  fdt->ft_fds[STDIN_FILENO].sysFd = STDIN_FILENO;
668  fdt->ft_fds[STDOUT_FILENO].sysFd = STDOUT_FILENO;
669  fdt->ft_fds[STDERR_FILENO].sysFd = STDERR_FILENO;
670  FD_SET(STDIN_FILENO, fdt->proc_fds);
671  FD_SET(STDOUT_FILENO, fdt->proc_fds);
672  FD_SET(STDERR_FILENO, fdt->proc_fds);
673}
674
675static void copy_fds(const struct fd_table_s *new_fdt, const struct fd_table_s *old_fdt)
676{
677  unsigned int sz;
678
679  sz = new_fdt->max_fds * sizeof(struct file_table_s);
680  if (sz)
681    {
682      (void)memcpy_s(new_fdt->ft_fds, sz, old_fdt->ft_fds, sz);
683    }
684  (void)memcpy_s(new_fdt->proc_fds, sizeof(fd_set), old_fdt->proc_fds, sizeof(fd_set));
685  (void)memcpy_s(new_fdt->cloexec_fds, sizeof(fd_set), old_fdt->cloexec_fds, sizeof(fd_set));
686}
687
688static void copy_fd_table(struct fd_table_s *new_fdt, struct fd_table_s *old_fdt)
689{
690  copy_fds((const struct fd_table_s *)new_fdt, (const struct fd_table_s *)old_fdt);
691  for (int i = 0; i < new_fdt->max_fds; i++)
692    {
693      if (FD_ISSET(i, new_fdt->proc_fds))
694        {
695          int sysFd = GetAssociatedSystemFd(i);
696          if ((sysFd >= 0) && (sysFd < CONFIG_NFILE_DESCRIPTORS))
697            {
698              files_refer(sysFd);
699            }
700#if defined(LOSCFG_NET_LWIP_SACK)
701          if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)))
702            {
703              socks_refer(sysFd);
704            }
705#endif
706#if defined(LOSCFG_COMPAT_POSIX)
707          if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS)))
708            {
709#if defined(LOSCFG_IPC_CONTAINER)
710              if (OsCurrTaskGet()->cloneIpc)
711                {
712                  FD_CLR(i, new_fdt->proc_fds);
713                  new_fdt->ft_fds[i].sysFd = -1;
714                  continue;
715                }
716#endif
717              MqueueRefer(sysFd);
718            }
719#endif
720
721        }
722    }
723}
724
725static struct fd_table_s * alloc_fd_table(unsigned int numbers)
726{
727  struct fd_table_s *fdt;
728  void *data;
729
730  fdt = LOS_MemAlloc(m_aucSysMem0, sizeof(struct fd_table_s));
731  if (!fdt)
732    {
733      goto out;
734    }
735  fdt->max_fds = numbers;
736  if (!numbers)
737    {
738      fdt->ft_fds = NULL;
739      fdt->proc_fds = NULL;
740      fdt->cloexec_fds = NULL;
741      return fdt;
742    }
743  data = LOS_MemAlloc(m_aucSysMem0, numbers * sizeof(struct file_table_s));
744  if (!data)
745    {
746      goto out_fdt;
747    }
748  fdt->ft_fds = data;
749
750  for (int i = STDERR_FILENO + 1; i < numbers; i++)
751    {
752        fdt->ft_fds[i].sysFd = -1;
753    }
754
755  data = LOS_MemAlloc(m_aucSysMem0, 2 * sizeof(fd_set)); /* 2: proc_fds, cloexec_fds */
756  if (!data)
757    {
758      goto out_arr;
759    }
760  (VOID)memset_s(data, 2 * sizeof(fd_set), 0, 2 * sizeof(fd_set));
761  fdt->proc_fds = (fd_set *)data;
762  fdt->cloexec_fds = (fd_set *)((uintptr_t)data + sizeof(fd_set));
763
764  alloc_std_fd(fdt);
765
766  (void)sem_init(&fdt->ft_sem, 0, 1);
767
768  return fdt;
769
770out_arr:
771  (VOID)LOS_MemFree(m_aucSysMem0, fdt->ft_fds);
772out_fdt:
773  (VOID)LOS_MemFree(m_aucSysMem0, fdt);
774out:
775  return NULL;
776}
777
778struct files_struct *alloc_files(void)
779{
780  struct files_struct *files = LOS_MemAlloc(m_aucSysMem0, sizeof(struct files_struct));
781  if (!files)
782    {
783      ferr("malloc file_struct error\n");
784      return NULL;
785    }
786  files->count = 1;
787  files->file_lock = 0;
788  files->next_fd = 3;
789#ifdef VFS_USING_WORKDIR
790  spin_lock_init(&files->workdir_lock);
791  memset_s(files->workdir, PATH_MAX, 0, PATH_MAX);
792  files->workdir[0] = '/';
793#endif
794  files->fdt = alloc_fd_table(NR_OPEN_DEFAULT);
795  if (!files->fdt)
796    {
797      ferr("malloc fdt error\n");
798      (VOID)LOS_MemFree(m_aucSysMem0, files);
799      return NULL;
800    }
801#ifdef LOSCFG_CHROOT
802  if (VnodeGetRoot() != NULL)
803    {
804      VnodeGetRoot()->useCount++;
805    }
806  files->rootVnode = VnodeGetRoot();
807#endif
808
809  return files;
810}
811
812struct files_struct *dup_fd(struct files_struct *old_files)
813{
814  struct fd_table_s *old_fdt = NULL;
815  struct fd_table_s *new_fdt = NULL;
816  struct files_struct *files = NULL;
817  if((old_files == NULL) || (old_files->fdt == NULL) || (old_files->fdt->max_fds == 0))
818    {
819      return alloc_files();
820    }
821  files = LOS_MemAlloc(m_aucSysMem0, sizeof(struct files_struct));
822  if(!files)
823    {
824      ferr("malloc file_struct error\n");
825      return NULL;
826    }
827  files->count = 1;
828  files->file_lock = 0;
829  files->next_fd = old_files->next_fd;
830#ifdef VFS_USING_WORKDIR
831  spin_lock_init(&files->workdir_lock);
832  memset_s(files->workdir, PATH_MAX, 0, PATH_MAX);
833  strncpy_s(files->workdir, PATH_MAX - 1, old_files->workdir, PATH_MAX - 1);
834#endif
835  old_fdt = old_files->fdt;
836  new_fdt = alloc_fd_table(old_fdt->max_fds);
837  if(new_fdt == NULL)
838    {
839      PRINT_ERR("alloc fd_table failed\n");
840      (VOID)LOS_MemFree(m_aucSysMem0, files);
841      return NULL;
842    }
843  copy_fd_table(new_fdt, old_fdt);
844  files->fdt = new_fdt;
845#ifdef LOSCFG_CHROOT
846  if (old_files->rootVnode != NULL)
847    {
848      old_files->rootVnode->useCount++;
849    }
850  files->rootVnode = old_files->rootVnode;
851#endif
852
853  return files;
854}
855
856/****************************************************************************
857 * Name: delete_files
858 *
859 * Description:
860 *   Close a current process's fd specified by struct files.
861 *   And delete files struct.
862 *
863 ****************************************************************************/
864void delete_files(struct files_struct *files)
865{
866  if (files == NULL)
867    {
868      return;
869    }
870
871#ifdef LOSCFG_CHROOT
872  if ((files->rootVnode != NULL) && (files->rootVnode->useCount > 0))
873    {
874      files->rootVnode->useCount--;
875    }
876#endif
877
878  if (files->fdt == NULL)
879    {
880      goto out_file;
881    }
882
883  for (int i = 0; i < files->fdt->max_fds; i++)
884    {
885      if (FD_ISSET(i, files->fdt->proc_fds))
886        {
887          int sysFd = DisassociateProcessFd(i);
888          close(sysFd);
889          FreeProcessFd(i);
890        }
891    }
892
893  (VOID)sem_destroy(&files->fdt->ft_sem);
894  (VOID)LOS_MemFree(m_aucSysMem0, files->fdt->ft_fds);
895  (VOID)LOS_MemFree(m_aucSysMem0, files->fdt->proc_fds);
896  (VOID)LOS_MemFree(m_aucSysMem0, files->fdt);
897out_file:
898  (VOID)LOS_MemFree(m_aucSysMem0, files);
899  return;
900}
901
902struct files_struct *create_files_snapshot(const struct files_struct *old_files)
903{
904  struct fd_table_s *old_fdt = NULL;
905  struct fd_table_s *new_fdt = NULL;
906  struct files_struct *files = NULL;
907  if ((old_files == NULL) || (old_files->fdt == NULL) || (old_files->fdt->max_fds == 0))
908    {
909      return NULL;
910    }
911  files = LOS_MemAlloc(m_aucSysMem0, sizeof(struct files_struct));
912  if (!files)
913    {
914      PRINT_ERR("malloc file_struct error\n");
915      return NULL;
916    }
917  files->count = 1;
918  files->file_lock = 0;
919  files->next_fd = old_files->next_fd;
920#ifdef VFS_USING_WORKDIR
921  spin_lock_init(&files->workdir_lock);
922  memset_s(files->workdir, PATH_MAX, 0, PATH_MAX);
923  strncpy_s(files->workdir, PATH_MAX - 1, old_files->workdir, PATH_MAX - 1);
924#endif
925  old_fdt = old_files->fdt;
926  new_fdt = alloc_fd_table(old_fdt->max_fds);
927  if (new_fdt == NULL)
928    {
929      PRINT_ERR("alloc fd_table failed\n");
930      (VOID)LOS_MemFree(m_aucSysMem0, files);
931      return NULL;
932    }
933  copy_fds((const struct fd_table_s *)new_fdt, (const struct fd_table_s *)old_fdt);
934  files->fdt = new_fdt;
935#ifdef LOSCFG_CHROOT
936  if (old_files->rootVnode != NULL)
937    {
938      old_files->rootVnode->useCount++;
939    }
940  files->rootVnode = old_files->rootVnode;
941#endif
942
943  return files;
944
945}
946
947void delete_files_snapshot(struct files_struct *files)
948{
949  if (files == NULL)
950    {
951      return;
952    }
953  if (files->fdt == NULL)
954    {
955      goto out_file;
956    }
957
958  (VOID)sem_destroy(&files->fdt->ft_sem);
959  (VOID)LOS_MemFree(m_aucSysMem0, files->fdt->ft_fds);
960  (VOID)LOS_MemFree(m_aucSysMem0, files->fdt->proc_fds);
961  (VOID)LOS_MemFree(m_aucSysMem0, files->fdt);
962out_file:
963  (VOID)LOS_MemFree(m_aucSysMem0, files);
964  return;
965}
966