xref: /third_party/NuttX/fs/tmpfs/fs_tmpfs.c (revision beacf11b)
1/****************************************************************************
2 * fs/tmpfs/fs_tmpfs.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/****************************************************************************
22 * Included Files
23 ****************************************************************************/
24#include <string.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <assert.h>
28#include <unistd.h>
29#include <limits.h>
30#include <sys/types.h>
31#include <sys/time.h>
32#include <linux/spinlock.h>
33#include <sys/statfs.h>
34#include "fs/dirent_fs.h"
35#include "fs/mount.h"
36#include "fs/file.h"
37#include "fs/fs.h"
38#include "los_tables.h"
39#include "fs_tmpfs.h"
40#include "los_vm_filemap.h"
41#include "user_copy.h"
42
43#ifdef LOSCFG_FS_RAMFS
44
45/****************************************************************************
46 * Pre-processor Definitions
47 ****************************************************************************/
48/*
49#if CONFIG_FS_TMPFS_DIRECTORY_FREEGUARD <= CONFIG_FS_TMPFS_DIRECTORY_ALLOCGUARD
50#  warning CONFIG_FS_TMPFS_DIRECTORY_FREEGUARD needs to be > ALLOCGUARD
51#endif
52
53#if CONFIG_FS_TMPFS_FILE_FREEGUARD <= CONFIG_FS_TMPFS_FILE_ALLOCGUARD
54#  warning CONFIG_FS_TMPFS_FILE_FREEGUARD needs to be > ALLOCGUARD
55#endif
56*/
57#define tmpfs_lock_file(tfo) \
58           (tmpfs_lock_object((struct tmpfs_object_s *)tfo))
59#define tmpfs_lock_directory(tdo) \
60           (tmpfs_lock_object((struct tmpfs_object_s *)tdo))
61#define tmpfs_unlock_file(tfo) \
62           (tmpfs_unlock_object((struct tmpfs_object_s *)tfo))
63#define tmpfs_unlock_directory(tdo) \
64           (tmpfs_unlock_object((struct tmpfs_object_s *)tdo))
65
66/****************************************************************************
67 * Private Function Prototypes
68 ****************************************************************************/
69
70/* TMPFS helpers */
71
72static void tmpfs_lock_reentrant(struct tmpfs_sem_s *sem);
73static void tmpfs_lock(struct tmpfs_s *fs);
74static void tmpfs_unlock_reentrant(struct tmpfs_sem_s *sem);
75static void tmpfs_unlock(struct tmpfs_s *fs);
76static void tmpfs_lock_object(struct tmpfs_object_s *to);
77static void tmpfs_unlock_object(struct tmpfs_object_s *to);
78static void tmpfs_release_lockedobject(struct tmpfs_object_s *to);
79static void tmpfs_release_lockedfile(struct tmpfs_file_s *tfo);
80static struct tmpfs_dirent_s *tmpfs_find_dirent(struct tmpfs_directory_s *tdo,
81              const char *name);
82static int  tmpfs_remove_dirent(struct tmpfs_directory_s *tdo,
83              struct tmpfs_object_s *to);
84static int  tmpfs_add_dirent(struct tmpfs_directory_s **tdo,
85              struct tmpfs_object_s *to, const char *name);
86static struct tmpfs_file_s *tmpfs_alloc_file(void);
87static int tmpfs_create_file(struct tmpfs_s *fs,
88                             const char *relpath,
89                             struct tmpfs_directory_s *parent_input,
90                             struct tmpfs_file_s **tfo);
91
92static struct tmpfs_directory_s *tmpfs_alloc_directory(void);
93static int tmpfs_create_directory(struct tmpfs_s *fs,
94                                  const char *relpath,
95                                  struct tmpfs_directory_s *parent,
96                                  struct tmpfs_directory_s **tdo);
97
98static int  tmpfs_find_object(struct tmpfs_s *fs,
99              const char *relpath, struct tmpfs_object_s **object,
100              struct tmpfs_directory_s **parent);
101static int  tmpfs_find_file(struct tmpfs_s *fs,
102              const char *relpath,
103              struct tmpfs_file_s **tfo,
104              struct tmpfs_directory_s **parent);
105static int  tmpfs_find_directory(struct tmpfs_s *fs,
106              const char *relpath,
107              struct tmpfs_directory_s **tdo,
108              struct tmpfs_directory_s **parent);
109
110/* File system operations */
111
112int tmpfs_close(struct file *filep);
113off_t tmpfs_seek(struct file *filep, off_t offset, int whence);
114int tmpfs_ioctl(struct file *filep, int cmd, unsigned long arg);
115int tmpfs_sync(struct file *filep);
116int tmpfs_closedir(struct Vnode *node, struct fs_dirent_s *dir);
117int tmpfs_rewinddir(struct Vnode *vp, struct fs_dirent_s *dir);
118int tmpfs_truncate(struct Vnode *vp, off_t len);
119
120int  tmpfs_mount(struct Mount *mnt, struct Vnode *device, const void *data);
121int  tmpfs_unmount(struct Mount *mnt, struct Vnode **blkdriver);
122
123int tmpfs_lookup(struct Vnode *parent, const char *name, int len, struct Vnode **vpp);
124ssize_t tmpfs_write(struct file *filep, const char *buffer, size_t buflen);
125ssize_t tmpfs_read(struct file *filep, char *buffer, size_t buflen);
126ssize_t tmpfs_readpage(struct Vnode *vnode, char *buffer, off_t off);
127int tmpfs_stat(struct Vnode *vp, struct stat *st);
128int tmpfs_opendir(struct Vnode *vp, struct fs_dirent_s *dir);
129int tmpfs_readdir(struct Vnode *vp, struct fs_dirent_s *dir);
130int tmpfs_rename(struct Vnode *oldVnode, struct Vnode *newParent, const char *oldname, const char *newname);
131int tmpfs_mkdir(struct Vnode *parent, const char *relpath, mode_t mode, struct Vnode **vpp);
132int tmpfs_create(struct Vnode *dvp, const char *path, int mode, struct Vnode **vpp);
133int tmpfs_unlink(struct Vnode *parent, struct Vnode *node, const char *relpath);
134int tmpfs_rmdir(struct Vnode *parent, struct Vnode *target, const char *dirname);
135int tmpfs_reclaim(struct Vnode *vp);
136
137int tmpfs_statfs(struct Mount *mp, struct statfs *sbp);
138
139static void tmpfs_stat_common(struct tmpfs_object_s *to,
140                              struct stat *buf);
141
142/****************************************************************************
143 * Public Data
144 ****************************************************************************/
145const struct MountOps tmpfs_operations = {
146    .Mount = tmpfs_mount,
147    .Unmount = tmpfs_unmount,
148    .Statfs = tmpfs_statfs,
149};
150
151struct VnodeOps tmpfs_vops = {
152    .Lookup = tmpfs_lookup,
153    .Getattr = tmpfs_stat,
154    .Opendir = tmpfs_opendir,
155    .Readdir = tmpfs_readdir,
156    .ReadPage = tmpfs_readpage,
157    .WritePage = NULL,
158    .Rename = tmpfs_rename,
159    .Mkdir = tmpfs_mkdir,
160    .Create = tmpfs_create,
161    .Unlink =  tmpfs_unlink,
162    .Rmdir = tmpfs_rmdir,
163    .Reclaim = tmpfs_reclaim,
164    .Closedir = tmpfs_closedir,
165    .Close = NULL,
166    .Rewinddir = tmpfs_rewinddir,
167    .Truncate = tmpfs_truncate,
168};
169
170struct file_operations_vfs tmpfs_fops = {
171    .seek = tmpfs_seek,
172    .write = tmpfs_write,
173    .read = tmpfs_read,
174    .ioctl = tmpfs_ioctl,
175    .mmap = OsVfsFileMmap,
176    .close = tmpfs_close,
177    .fsync = tmpfs_sync,
178};
179
180static struct tmpfs_s tmpfs_superblock = {0};
181
182/****************************************************************************
183 * Name: tmpfs_timestamp
184 ****************************************************************************/
185
186static time_t tmpfs_timestamp(void)
187{
188  struct timeval tv;
189
190  (void)gettimeofday(&tv, (struct timezone *)NULL);
191
192  return (time_t)(tv.tv_sec);
193}
194
195/****************************************************************************
196 * Name: tmpfs_lock_reentrant
197 ****************************************************************************/
198
199static void tmpfs_lock_reentrant(struct tmpfs_sem_s *sem)
200{
201  pid_t me;
202
203  /* Do we already hold the semaphore? */
204
205  me = getpid();
206  if (me == sem->ts_holder)
207    {
208      /* Yes... just increment the count */
209
210      sem->ts_count++;
211      DEBUGASSERT(sem->ts_count > 0);
212    }
213
214  /* Take the semaphore (perhaps waiting) */
215
216  else
217    {
218      while (sem_wait(&sem->ts_sem) != 0)
219        {
220          /* The only case that an error should occur here is if the wait
221           * was awakened by a signal.
222           */
223
224          DEBUGASSERT(get_errno() == EINTR);
225        }
226
227      /* No we hold the semaphore */
228
229      sem->ts_holder = me;
230      sem->ts_count  = 1;
231    }
232}
233
234/****************************************************************************
235 * Name: tmpfs_lock
236 ****************************************************************************/
237
238static void tmpfs_lock(struct tmpfs_s *fs)
239{
240  tmpfs_lock_reentrant(&fs->tfs_exclsem);
241}
242
243/****************************************************************************
244 * Name: tmpfs_lock_object
245 ****************************************************************************/
246
247static void tmpfs_lock_object(struct tmpfs_object_s *to)
248{
249  tmpfs_lock_reentrant(&to->to_exclsem);
250}
251
252/****************************************************************************
253 * Name: tmpfs_unlock_reentrant
254 ****************************************************************************/
255
256static void tmpfs_unlock_reentrant(struct tmpfs_sem_s *sem)
257{
258  DEBUGASSERT(sem->ts_holder == getpid());
259
260  /* Is this our last count on the semaphore? */
261
262  if (sem->ts_count > 1)
263    {
264      /* No.. just decrement the count */
265
266      sem->ts_count--;
267    }
268
269  /* Yes.. then we can really release the semaphore */
270
271  else
272    {
273      sem->ts_holder = TMPFS_NO_HOLDER;
274      sem->ts_count  = 0;
275      sem_post(&sem->ts_sem);
276    }
277}
278
279/****************************************************************************
280 * Name: tmpfs_unlock
281 ****************************************************************************/
282
283static void tmpfs_unlock(struct tmpfs_s *fs)
284{
285  tmpfs_unlock_reentrant(&fs->tfs_exclsem);
286}
287
288/****************************************************************************
289 * Name: tmpfs_unlock_object
290 ****************************************************************************/
291
292static void tmpfs_unlock_object(struct tmpfs_object_s *to)
293{
294  tmpfs_unlock_reentrant(&to->to_exclsem);
295}
296
297/****************************************************************************
298 * Name: tmpfs_release_lockedobject
299 ****************************************************************************/
300
301static void tmpfs_release_lockedobject(struct tmpfs_object_s *to)
302{
303  DEBUGASSERT(to && to->to_refs > 0);
304
305  /* Is this a file object? */
306
307  if (to->to_type == TMPFS_REGULAR)
308    {
309      tmpfs_release_lockedfile((struct tmpfs_file_s *)to);
310    }
311  else
312    {
313      if(to->to_refs > 0)
314        {
315          to->to_refs--;
316        }
317      tmpfs_unlock_object(to);
318    }
319}
320
321/****************************************************************************
322 * Name: tmpfs_release_lockedfile
323 ****************************************************************************/
324
325static void tmpfs_release_lockedfile(struct tmpfs_file_s *tfo)
326{
327  DEBUGASSERT(tfo && tfo->tfo_refs > 0);
328
329  /* If there are no longer any references to the file and the file has been
330   * unlinked from its parent directory, then free the file object now.
331   */
332
333  if (tfo->tfo_refs == 1 && (tfo->tfo_flags & TFO_FLAG_UNLINKED) != 0)
334    {
335      sem_destroy(&tfo->tfo_exclsem.ts_sem);
336      kmm_free(tfo->tfo_data);
337      kmm_free(tfo);
338    }
339
340  /* Otherwise, just decrement the reference count on the file object */
341
342  else
343    {
344      if(tfo->tfo_refs > 0)
345        {
346          tfo->tfo_refs--;
347        }
348      tmpfs_unlock_file(tfo);
349    }
350}
351
352/****************************************************************************
353 * Name: tmpfs_find_dirent
354 ****************************************************************************/
355
356static struct tmpfs_dirent_s *tmpfs_find_dirent(struct tmpfs_directory_s *tdo,
357                                                const char *name)
358{
359  LOS_DL_LIST *node;
360  struct tmpfs_dirent_s *tde;
361
362  /* Search the list of directory entries for a match */
363
364  for (node = tdo->tdo_entry.pstNext; node != &tdo->tdo_entry; node = node->pstNext)
365    {
366      tde = (struct tmpfs_dirent_s *)node;
367      if (tde->tde_inuse == true && strcmp(tde->tde_name, name) == 0)
368        {
369          return tde;
370        }
371    }
372
373  /* Return NULL if not found */
374
375  return NULL;
376}
377
378/****************************************************************************
379 * Name: tmpfs_remove_dirent
380 ****************************************************************************/
381
382static int tmpfs_remove_dirent(struct tmpfs_directory_s *tdo,
383                               struct tmpfs_object_s *to)
384{
385  struct tmpfs_dirent_s *tde;
386
387  /* Search the list of directory entries for a match */
388
389  tde = to->to_dirent;
390  if (tde == NULL)
391    {
392      return -ENONET;
393    }
394
395  /* Free the object name */
396
397  if (tde->tde_name != NULL)
398    {
399      kmm_free(tde->tde_name);
400      tde->tde_name = NULL;
401    }
402
403  if (tdo->tdo_count == 0)
404    {
405      LOS_ListDelete(&tde->tde_node);
406      kmm_free(tde);
407    }
408  else
409    {
410      tde->tde_inuse = false;
411      tde->tde_object = NULL;
412    }
413  if(tdo->tdo_nentries > 0)
414    {
415      tdo->tdo_nentries--;
416    }
417  return OK;
418}
419
420/****************************************************************************
421 * Name: tmpfs_add_dirent
422 ****************************************************************************/
423
424static int tmpfs_add_dirent(struct tmpfs_directory_s **tdo,
425                            struct tmpfs_object_s *to,
426                            const char *name)
427{
428  struct tmpfs_directory_s *parent;
429  struct tmpfs_dirent_s *tde;
430  char *newname;
431
432  /* Copy the name string so that it will persist as long as the
433   * directory entry.
434   */
435
436  newname = strdup(name);
437  if (newname == NULL)
438    {
439      return -ENOSPC;
440    }
441
442  tde = (struct tmpfs_dirent_s *)malloc(sizeof(struct tmpfs_dirent_s));
443  if (tde == NULL)
444    {
445      free(newname);
446      return -ENOSPC;
447    }
448
449  tde->tde_object = to;
450  tde->tde_name   = newname;
451  tde->tde_inuse  = true;
452  to->to_dirent   = tde;
453
454  /* Save the new object info in the new directory entry */
455
456  parent = *tdo;
457  LOS_ListTailInsert(&parent->tdo_entry, &tde->tde_node);
458  parent->tdo_nentries++;
459
460  /* Update directory times */
461
462  parent->tdo_ctime = parent->tdo_mtime = tmpfs_timestamp();
463
464  return OK;
465}
466
467/****************************************************************************
468 * Name: tmpfs_alloc_file
469 ****************************************************************************/
470
471static struct tmpfs_file_s *tmpfs_alloc_file(void)
472{
473  struct tmpfs_file_s *tfo;
474  size_t allocsize;
475
476  /* Create a new zero length file object */
477
478  allocsize = sizeof(struct tmpfs_file_s);
479  tfo = (struct tmpfs_file_s *)kmm_malloc(allocsize);
480  if (tfo == NULL)
481    {
482      return NULL;
483    }
484
485  /* Initialize the new file object.  NOTE that the initial state is
486   * locked with one reference count.
487   */
488
489  tfo->tfo_atime = tmpfs_timestamp();
490  tfo->tfo_mtime = tfo->tfo_atime;
491  tfo->tfo_ctime = tfo->tfo_atime;
492  tfo->tfo_type  = TMPFS_REGULAR;
493  tfo->tfo_refs  = 1;
494  tfo->tfo_flags = 0;
495  tfo->tfo_size  = 0;
496  tfo->tfo_data  = NULL;
497
498  tfo->tfo_exclsem.ts_holder = getpid();
499  tfo->tfo_exclsem.ts_count  = 1;
500  if (sem_init(&tfo->tfo_exclsem.ts_sem, 0, 0) != 0)
501    {
502      PRINT_ERR("%s %d, sem_init failed!\n", __FUNCTION__, __LINE__);
503      kmm_free(tfo);
504      return NULL;
505    }
506
507  return tfo;
508}
509
510/****************************************************************************
511 * Name: tmpfs_create_file
512 ****************************************************************************/
513
514static int tmpfs_create_file(struct tmpfs_s *fs,
515                             const char *relpath,
516                             struct tmpfs_directory_s *parent_input,
517                             struct tmpfs_file_s **tfo)
518{
519  struct tmpfs_directory_s *parent;
520  struct tmpfs_file_s *newtfo;
521  struct tmpfs_dirent_s *tde;
522  char *copy;
523  int ret;
524
525  /* Duplicate the path variable so that we can modify it */
526
527  copy = strdup(relpath);
528  if (copy == NULL)
529    {
530      return -ENOSPC;
531    }
532
533  /* Separate the path into the file name and the path to the parent
534   * directory.
535   */
536  if (parent_input == NULL)
537    {
538      /* No subdirectories... use the root directory */
539      parent = (struct tmpfs_directory_s *)fs->tfs_root.tde_object;
540    }
541  else
542    {
543      parent = parent_input;
544    }
545  if (parent == NULL)
546    {
547      ret = -EEXIST;
548      goto errout_with_copy;
549    }
550  tmpfs_lock_directory(parent);
551  parent->tdo_refs++;
552
553  /* Verify that no object of this name already exists in the directory */
554  tde = tmpfs_find_dirent(parent, copy);
555  if (tde != NULL)
556    {
557      /* Something with this name already exists in the directory.
558       * OR perhaps some fatal error occurred.
559       */
560
561      ret = -EEXIST;
562      goto errout_with_parent;
563    }
564
565  /* Allocate an empty file.  The initial state of the file is locked with one
566   * reference count.
567   */
568
569  newtfo = tmpfs_alloc_file();
570  if (newtfo == NULL)
571    {
572      ret = -ENOSPC;
573      goto errout_with_parent;
574    }
575
576  /* Then add the new, empty file to the directory */
577
578  ret = tmpfs_add_dirent(&parent, (struct tmpfs_object_s *)newtfo, copy);
579  if (ret < 0)
580    {
581      goto errout_with_file;
582    }
583
584  /* Release the reference and lock on the parent directory */
585  if (parent->tdo_refs > 0)
586    {
587      parent->tdo_refs--;
588    }
589  tmpfs_unlock_directory(parent);
590
591  /* Free the copy of the relpath and return success */
592
593  kmm_free(copy);
594  *tfo = newtfo;
595  return OK;
596
597  /* Error exits */
598
599errout_with_file:
600  sem_destroy(&newtfo->tfo_exclsem.ts_sem);
601  kmm_free(newtfo);
602
603errout_with_parent:
604  if (parent->tdo_refs > 0)
605  {
606    parent->tdo_refs--;
607  }
608  tmpfs_unlock_directory(parent);
609
610errout_with_copy:
611  kmm_free(copy);
612  return ret;
613}
614
615/****************************************************************************
616 * Name: tmpfs_alloc_directory
617 ****************************************************************************/
618
619static struct tmpfs_directory_s *tmpfs_alloc_directory(void)
620{
621  struct tmpfs_directory_s *tdo;
622  size_t allocsize;
623
624  allocsize = sizeof(struct tmpfs_directory_s);
625  tdo = (struct tmpfs_directory_s *)kmm_malloc(allocsize);
626  if (tdo == NULL)
627    {
628      return NULL;
629    }
630
631  /* Initialize the new directory object */
632
633  tdo->tdo_atime    = tmpfs_timestamp();
634  tdo->tdo_mtime    = tdo->tdo_mtime;
635  tdo->tdo_ctime    =  tdo->tdo_mtime;
636  tdo->tdo_type     = TMPFS_DIRECTORY;
637  tdo->tdo_refs     = 0;
638  tdo->tdo_nentries = 0;
639  tdo->tdo_count    = 0;
640  LOS_ListInit(&tdo->tdo_entry);
641
642  tdo->tdo_exclsem.ts_holder = TMPFS_NO_HOLDER;
643  tdo->tdo_exclsem.ts_count  = 0;
644  if (sem_init(&tdo->tdo_exclsem.ts_sem, 0, 1) != 0)
645    {
646      PRINT_ERR("%s %d, sem_init failed!\n", __FUNCTION__, __LINE__);
647      kmm_free(tdo);
648      return NULL;
649    }
650  return tdo;
651}
652
653/****************************************************************************
654 * Name: tmpfs_create_directory
655 ****************************************************************************/
656
657static int tmpfs_create_directory(struct tmpfs_s *fs,
658                                  const char *relpath,
659                                  struct tmpfs_directory_s *parent_input,
660                                  struct tmpfs_directory_s **tdo)
661{
662  struct tmpfs_directory_s *parent;
663  struct tmpfs_directory_s *newtdo;
664  struct tmpfs_dirent_s *tde;
665  char *copy;
666  int ret;
667
668  /* Duplicate the path variable so that we can modify it */
669
670  copy = strdup(relpath);
671  if (copy == NULL)
672    {
673      return -ENOSPC;
674    }
675
676  /* Separate the path into the file name and the path to the parent
677   * directory.
678   */
679  if (parent_input == NULL)
680    {
681      /* No subdirectories... use the root directory */
682
683      parent = (struct tmpfs_directory_s *)fs->tfs_root.tde_object;
684    }
685  else
686    {
687      parent = parent_input;
688    }
689
690  /* Verify that no object of this name already exists in the directory */
691  if (parent == NULL)
692    {
693      ret = -EEXIST;
694      goto errout_with_copy;
695    }
696  tmpfs_lock_directory(parent);
697  parent->tdo_refs++;
698  tde = tmpfs_find_dirent(parent, copy);
699  if (tde != NULL)
700    {
701      /* Something with this name already exists in the directory.
702       * OR perhaps some fatal error occurred.
703       */
704
705      ret = -EEXIST;
706
707      goto errout_with_parent;
708    }
709
710  /* Allocate an empty directory object.  NOTE that there is no reference on
711   * the new directory and the object is not locked.
712   */
713
714  newtdo = tmpfs_alloc_directory();
715  if (newtdo == NULL)
716    {
717      ret = -ENOSPC;
718      goto errout_with_parent;
719    }
720
721  /* Then add the new, empty file to the directory */
722
723  ret = tmpfs_add_dirent(&parent, (struct tmpfs_object_s *)newtdo, copy);
724  if (ret < 0)
725    {
726      goto errout_with_directory;
727    }
728
729  /* Free the copy of the relpath, release our reference to the parent directory,
730   * and return success
731   */
732  if (parent->tdo_refs > 0)
733    {
734      parent->tdo_refs--;
735    }
736  tmpfs_unlock_directory(parent);
737  kmm_free(copy);
738
739  /* Return the (unlocked, unreferenced) directory object to the caller */
740
741  if (tdo != NULL)
742    {
743      *tdo = newtdo;
744    }
745
746  return OK;
747
748  /* Error exits */
749
750errout_with_directory:
751  sem_destroy(&newtdo->tdo_exclsem.ts_sem);
752  kmm_free(newtdo);
753
754errout_with_parent:
755  if (parent->tdo_refs > 0)
756    {
757      parent->tdo_refs--;
758    }
759  tmpfs_unlock_directory(parent);
760
761errout_with_copy:
762  kmm_free(copy);
763  return ret;
764}
765
766/****************************************************************************
767 * Name: tmpfs_find_object
768 ****************************************************************************/
769
770static int tmpfs_find_object(struct tmpfs_s *fs,
771                             const char *relpath,
772                             struct tmpfs_object_s **object,
773                             struct tmpfs_directory_s **parent)
774{
775  struct tmpfs_object_s *to = NULL;
776  struct tmpfs_dirent_s *tde;
777  struct tmpfs_directory_s *tdo = NULL;
778  struct tmpfs_directory_s *next_tdo;
779  char *segment;
780  char *next_segment;
781  char *tkptr;
782  char *copy;
783
784  /* Make a copy of the path (so that we can modify it via strtok) */
785
786  copy = strdup(relpath);
787  if (copy == NULL)
788    {
789      return -ENOSPC;
790    }
791
792  /* Traverse the file system for any object with the matching name */
793
794  to       = fs->tfs_root.tde_object;
795  next_tdo = (struct tmpfs_directory_s *)fs->tfs_root.tde_object;
796  tdo      = next_tdo;
797  for (segment =  strtok_r(copy, "/", &tkptr);
798       segment != NULL;
799       segment = next_segment)
800    {
801      /* Get the next segment after the one we are currently working on.
802       * This will be NULL is we are working on the final segment of the
803       * relpath.
804       */
805
806      next_segment = strtok_r(NULL, "/", &tkptr);
807
808      /* Search the next directory. */
809
810      tdo = next_tdo;
811
812      /* Find the TMPFS object with the next segment name in the current
813       * directory.
814       */
815
816      tde = tmpfs_find_dirent(tdo, segment);
817      if (tde == NULL)
818        {
819          /* No object with this name exists in the directory. */
820
821          kmm_free(copy);
822          return -ENOENT;
823        }
824
825      to = tde->tde_object;
826
827      /* Is this object another directory? */
828
829      if (to->to_type != TMPFS_DIRECTORY)
830        {
831          /* No.  Was this the final segment in the path? */
832
833          if (next_segment == NULL)
834            {
835              /* Then we can break out of the loop now */
836
837               break;
838            }
839
840          /* No, this was not the final segement of the relpath.
841           * We cannot continue the search if any of the intermediate
842           * segments do no correspond to directories.
843           */
844
845          kmm_free(copy);
846          return -ENOTDIR;
847        }
848
849      /* Search this directory for the next segement.  If we
850       * exit the loop, tdo will still refer to the parent
851       * directory of to.
852       */
853
854      next_tdo = (struct tmpfs_directory_s *)to;
855    }
856
857  /* When we exit this loop (successfully), to will point to the TMPFS
858   * object associated with the terminal segment of the relpath.
859   * Increment the reference count on the located object.
860   */
861
862  /* Free the dup'ed string */
863
864  kmm_free(copy);
865
866  /* Return what we found */
867
868  if (parent)
869    {
870      if (tdo != NULL)
871        {
872          /* Get exclusive access to the parent and increment the reference
873           * count on the object.
874           */
875
876          tmpfs_lock_directory(tdo);
877          tdo->tdo_refs++;
878        }
879
880      *parent = tdo;
881    }
882
883  if (object)
884    {
885      if (to != NULL)
886        {
887          /* Get exclusive access to the object and increment the reference
888           * count on the object.
889           */
890
891          tmpfs_lock_object(to);
892          to->to_refs++;
893        }
894
895      *object = to;
896    }
897
898  return OK;
899}
900
901/****************************************************************************
902 * Name: tmpfs_find_file
903 ****************************************************************************/
904
905static int tmpfs_find_file(struct tmpfs_s *fs,
906                           const char *relpath,
907                           struct tmpfs_file_s **tfo,
908                           struct tmpfs_directory_s **parent)
909{
910  struct tmpfs_object_s *to;
911  int ret;
912
913  /* Find the object at this path.  If successful, tmpfs_find_object() will
914   * lock both the object and the parent directory and will increment the
915   * reference count on both.
916   */
917
918  ret = tmpfs_find_object(fs, relpath, &to, parent);
919  if (ret >= 0)
920    {
921      /* We found it... but is it a regular file? */
922
923      if (to->to_type != TMPFS_REGULAR)
924        {
925          /* No... unlock the object and its parent and return an error */
926
927          tmpfs_release_lockedobject(to);
928
929          if (parent)
930            {
931              struct tmpfs_directory_s *tdo = *parent;
932
933              tdo->tdo_refs--;
934              tmpfs_unlock_directory(tdo);
935            }
936
937          ret = -EISDIR;
938        }
939
940      /* Return the verified file object */
941
942      *tfo = (struct tmpfs_file_s *)to;
943    }
944
945  return ret;
946}
947
948/****************************************************************************
949 * Name: tmpfs_find_directory
950 ****************************************************************************/
951
952static int tmpfs_find_directory(struct tmpfs_s *fs,
953                           const char *relpath,
954                           struct tmpfs_directory_s **tdo,
955                           struct tmpfs_directory_s **parent)
956{
957  struct tmpfs_object_s *to;
958  int ret;
959
960  /* Find the object at this path */
961
962  ret = tmpfs_find_object(fs, relpath, &to, parent);
963  if (ret >= 0)
964    {
965      /* We found it... but is it a regular file? */
966
967      if (to->to_type != TMPFS_DIRECTORY)
968        {
969          /* No... unlock the object and its parent and return an error */
970
971          tmpfs_release_lockedobject(to);
972
973          if (parent)
974            {
975              struct tmpfs_directory_s *tmptdo = *parent;
976
977              tmptdo->tdo_refs--;
978              tmpfs_unlock_directory(tmptdo);
979            }
980
981          ret = -ENOTDIR;
982        }
983
984      /* Return the verified file object */
985
986      *tdo = (struct tmpfs_directory_s *)to;
987    }
988
989  return ret;
990}
991
992/****************************************************************************
993 * Name: tmpfs_close
994 ****************************************************************************/
995
996int tmpfs_close(struct file *filep)
997{
998  struct tmpfs_file_s *tfo;
999
1000  DEBUGASSERT(filep != NULL);
1001
1002  /* Recover our private data from the struct file instance */
1003  tfo = (struct tmpfs_file_s *)(filep->f_vnode->data);
1004  if (tfo == NULL)
1005    {
1006      return -EINVAL;
1007    }
1008  /* Get exclusive access to the file */
1009
1010  tmpfs_lock_file(tfo);
1011
1012  /* Decrement the reference count on the file */
1013
1014  if (tfo->tfo_refs > 0)
1015    {
1016      tfo->tfo_refs--;
1017    }
1018
1019  /* If the reference count decremented to zero and the file has been
1020   * unlinked, then free the file allocation now.
1021   */
1022
1023  if (tfo->tfo_refs == 0 && (tfo->tfo_flags & TFO_FLAG_UNLINKED) != 0)
1024    {
1025      /* Free the file object while we hold the lock?  Weird but this
1026       * should be safe because the object is unlinked and could not
1027       * have any other references.
1028       */
1029
1030      (void)sem_destroy(&tfo->tfo_exclsem.ts_sem);
1031      kmm_free(tfo->tfo_data);
1032      kmm_free(tfo);
1033      return OK;
1034    }
1035
1036  /* Release the lock on the file */
1037
1038  tmpfs_unlock_file(tfo);
1039  return OK;
1040}
1041
1042/****************************************************************************
1043 * Name: tmpfs_read
1044 ****************************************************************************/
1045
1046ssize_t tmpfs_read(struct file *filep, char *buffer, size_t buflen)
1047{
1048  struct tmpfs_file_s *tfo;
1049  ssize_t nread;
1050  loff_t startpos;
1051  loff_t endpos;
1052
1053  DEBUGASSERT(filep->f_vnode != NULL);
1054
1055  /* Recover our private data from the struct file instance */
1056
1057  tfo = (struct tmpfs_file_s *)(filep->f_vnode->data);
1058  if (tfo == NULL)
1059    {
1060      return -EINVAL;
1061    }
1062  if (filep->f_pos >= tfo->tfo_size || buflen == 0)
1063    {
1064      return 0;
1065    }
1066
1067  /* Get exclusive access to the file */
1068
1069  tmpfs_lock_file(tfo);
1070
1071  /* Handle attempts to read beyond the end of the file. */
1072
1073  startpos = filep->f_pos;
1074  nread    = buflen;
1075  endpos   = startpos + buflen;
1076
1077  if (endpos > tfo->tfo_size)
1078    {
1079      endpos = tfo->tfo_size;
1080      nread  = endpos - startpos;
1081    }
1082
1083  /* Copy data from the memory object to the user buffer */
1084
1085  if (LOS_CopyFromKernel(buffer, buflen, &tfo->tfo_data[startpos], nread) != 0)
1086    {
1087      tmpfs_unlock_file(tfo);
1088      return -EINVAL;
1089    }
1090  filep->f_pos += nread;
1091
1092  /* Update the node's access time */
1093
1094  tfo->tfo_atime = tmpfs_timestamp();
1095
1096  /* Release the lock on the file */
1097
1098  tmpfs_unlock_file(tfo);
1099  return nread;
1100}
1101
1102/****************************************************************************
1103 * Name: tmpfs_readpage
1104 ****************************************************************************/
1105
1106ssize_t tmpfs_readpage(struct Vnode *vnode, char *buffer, off_t off)
1107{
1108  struct tmpfs_file_s *tfo;
1109  ssize_t nread;
1110  loff_t startpos;
1111  loff_t endpos;
1112
1113  DEBUGASSERT(vnode->data != NULL);
1114
1115  /* Recover our private data from the vnode */
1116
1117  tfo = (struct tmpfs_file_s *)(vnode->data);
1118  if (tfo == NULL)
1119    {
1120      return -EINVAL;
1121    }
1122  if (off >= tfo->tfo_size)
1123    {
1124      return 0;
1125    }
1126
1127  /* Get exclusive access to the file */
1128
1129  tmpfs_lock_file(tfo);
1130
1131  /* Handle attempts to read beyond the end of the file. */
1132
1133  startpos = off;
1134  nread    = PAGE_SIZE;
1135  endpos   = startpos + PAGE_SIZE;
1136
1137  if (endpos > tfo->tfo_size)
1138    {
1139      endpos = tfo->tfo_size;
1140      nread  = endpos - startpos;
1141    }
1142
1143  /* Copy data from the memory object to the user buffer */
1144
1145  if (LOS_CopyFromKernel(buffer, PAGE_SIZE, &tfo->tfo_data[startpos], nread) != 0)
1146    {
1147      tmpfs_unlock_file(tfo);
1148      return -EINVAL;
1149    }
1150
1151  /* Update the node's access time */
1152
1153  tfo->tfo_atime = tmpfs_timestamp();
1154
1155  /* Release the lock on the file */
1156
1157  tmpfs_unlock_file(tfo);
1158  return nread;
1159}
1160
1161
1162/****************************************************************************
1163 * Name: tmpfs_create
1164 ****************************************************************************/
1165
1166int tmpfs_create(struct Vnode *dvp, const char *path, int mode, struct Vnode **vpp)
1167{
1168    struct Vnode *vp = NULL;
1169    struct tmpfs_file_s *tfo;
1170    struct tmpfs_s *fs;
1171    int ret = 0;
1172    struct tmpfs_directory_s *parent_tdo = NULL;
1173
1174    if (dvp == NULL)
1175      {
1176        return -ENOENT;
1177      }
1178
1179    fs = dvp->originMount->data;
1180    if (fs == NULL)
1181      {
1182        return -ENOENT;
1183      }
1184
1185    tmpfs_lock(fs);
1186
1187    if (dvp->data != NULL)
1188      {
1189        parent_tdo = (struct tmpfs_directory_s *)(dvp->data);
1190      }
1191
1192    ret = tmpfs_create_file(fs, path, parent_tdo, &tfo);
1193    if (ret < 0)
1194      {
1195        goto errout_with_fslock;
1196      }
1197
1198    ret = VnodeAlloc(&tmpfs_vops, &vp);
1199    if (ret != 0)
1200      {
1201        tmpfs_unlock_file(tfo);
1202        goto errout_with_fslock;
1203      }
1204    vp->parent = dvp;
1205    vp->vop = dvp->vop;
1206    vp->fop = dvp->fop;
1207    vp->data = tfo;
1208    vp->originMount = dvp->originMount;
1209    vp->type = VNODE_TYPE_REG;
1210    tfo->mode = mode;
1211    vp->mode = tfo->mode;
1212    vp->gid = tfo->gid;
1213    vp->uid = tfo->uid;
1214
1215    ret = VfsHashInsert(vp, (uint32_t)tfo);
1216
1217    *vpp = vp;
1218    tmpfs_unlock_file(tfo);
1219errout_with_fslock:
1220    tmpfs_unlock(fs);
1221    return 0;
1222}
1223
1224
1225/****************************************************************************
1226 * Name: los_set_ramfs_unit
1227 ****************************************************************************/
1228
1229static spinlock_t tmpfs_alloc_unit_lock;
1230bool is_tmpfs_lock_init = false;
1231unsigned int g_tmpfs_alloc_unit = 0;
1232
1233void los_set_ramfs_unit(off_t size)
1234{
1235  if (is_tmpfs_lock_init && size >= 0)
1236    {
1237      spin_lock(&tmpfs_alloc_unit_lock);
1238      g_tmpfs_alloc_unit = size;
1239      spin_unlock(&tmpfs_alloc_unit_lock);
1240    }
1241}
1242
1243/****************************************************************************
1244 * Name: tmpfs_write
1245 ****************************************************************************/
1246
1247ssize_t tmpfs_write(struct file *filep, const char *buffer, size_t buflen)
1248{
1249  struct tmpfs_file_s *tfo;
1250  ssize_t nwritten;
1251  loff_t startpos;
1252  loff_t endpos;
1253  int ret;
1254  int alloc;
1255  char *data;
1256
1257  DEBUGASSERT(filep->f_vnode != NULL);
1258
1259  if (buflen == 0)
1260    {
1261      return 0;
1262    }
1263
1264  /* Recover our private data from the struct file instance */
1265  tfo = (struct tmpfs_file_s *)(filep->f_vnode->data);
1266  if (tfo == NULL)
1267    {
1268      return -EINVAL;
1269    }
1270  /* Get exclusive access to the file */
1271
1272  tmpfs_lock_file(tfo);
1273
1274  /* Handle attempts to write beyond the end of the file */
1275
1276  startpos = filep->f_pos;
1277  nwritten = buflen;
1278  endpos   = startpos + buflen;
1279
1280  if (startpos < 0)
1281    {
1282      ret = -EPERM;
1283      goto errout_with_lock;
1284    }
1285
1286  if (endpos > tfo->tfo_size)
1287    {
1288      spin_lock(&tmpfs_alloc_unit_lock);
1289      alloc = (g_tmpfs_alloc_unit > buflen) ? g_tmpfs_alloc_unit : buflen;
1290      spin_unlock(&tmpfs_alloc_unit_lock);
1291      data  = (char *)malloc(startpos + alloc);
1292      if (!data)
1293        {
1294          ret = -ENOSPC;
1295          goto errout_with_lock;
1296        }
1297      if (tfo->tfo_size)
1298        {
1299          ret = memcpy_s(data, startpos + alloc, tfo->tfo_data, tfo->tfo_size);
1300          if (ret != EOK)
1301            {
1302              ret = -1;
1303              free(data);
1304              goto errout_with_lock;
1305            }
1306          free(tfo->tfo_data);
1307        }
1308      if (startpos > tfo->tfo_size)
1309        {
1310          (void)memset_s(data + tfo->tfo_size, startpos + alloc - tfo->tfo_size, 0, startpos - tfo->tfo_size);
1311        }
1312
1313      tfo->tfo_data = data;
1314      tfo->tfo_size = startpos + alloc;
1315    }
1316
1317  /* Copy data from the memory object to the user buffer */
1318  if (LOS_CopyToKernel(&tfo->tfo_data[startpos], nwritten, buffer, nwritten) != 0)
1319    {
1320      ret = -EINVAL;
1321      goto errout_with_lock;
1322    }
1323  filep->f_pos += nwritten;
1324
1325  /* Update the modified and access times of the node */
1326
1327  tfo->tfo_ctime = tfo->tfo_mtime = tmpfs_timestamp();
1328
1329  /* Release the lock on the file */
1330
1331  tmpfs_unlock_file(tfo);
1332  return nwritten;
1333
1334errout_with_lock:
1335  tmpfs_unlock_file(tfo);
1336  return (ssize_t)ret;
1337}
1338
1339/****************************************************************************
1340 * Name: tmpfs_seek
1341 ****************************************************************************/
1342
1343off_t tmpfs_seek(struct file *filep, off_t offset, int whence)
1344{
1345  struct tmpfs_file_s *tfo;
1346  off_t position;
1347
1348  DEBUGASSERT(filep->f_vnode != NULL);
1349
1350  /* Recover our private data from the struct file instance */
1351
1352  tfo = (struct tmpfs_file_s *)(filep->f_vnode->data);
1353  if (tfo == NULL)
1354    {
1355      return -EINVAL;
1356    }
1357  /* Map the offset according to the whence option */
1358
1359  switch (whence)
1360    {
1361      case SEEK_SET: /* The offset is set to offset bytes. */
1362          position = offset;
1363          break;
1364
1365      case SEEK_CUR: /* The offset is set to its current location plus
1366                      * offset bytes. */
1367          position = offset + filep->f_pos;
1368          break;
1369
1370      case SEEK_END: /* The offset is set to the size of the file plus
1371                      * offset bytes. */
1372          position = offset + tfo->tfo_size;
1373          break;
1374
1375      default:
1376          return -EINVAL;
1377    }
1378
1379  /* Attempts to set the position beyond the end of file will
1380   * work if the file is open for write access.
1381   *
1382   * REVISIT: This simple implementation has no per-open storage that
1383   * would be needed to retain the open flags.
1384   */
1385    if (position < 0)
1386    {
1387      return -EINVAL;
1388    }
1389
1390  /* Save the new file position */
1391
1392  filep->f_pos = position;
1393  return position;
1394}
1395
1396/****************************************************************************
1397 * Name: tmpfs_ioctl
1398 ****************************************************************************/
1399
1400int tmpfs_ioctl(struct file *filep, int cmd, unsigned long arg)
1401{
1402  return -EINVAL;
1403}
1404
1405/****************************************************************************
1406 * Name: tmpfs_sync
1407 ****************************************************************************/
1408
1409int tmpfs_sync(struct file *filep)
1410{
1411  return 0;
1412}
1413
1414/****************************************************************************
1415 * Name: tmpfs_opendir
1416 ****************************************************************************/
1417
1418int tmpfs_opendir(struct Vnode *vp, struct fs_dirent_s *dir)
1419{
1420  struct tmpfs_s *fs;
1421  struct tmpfs_directory_s *tdo;
1422  int ret = 0;
1423  struct fs_tmpfsdir_s *tmp;
1424
1425  DEBUGASSERT(vp != NULL && dir != NULL);
1426
1427  /* Get the mountpoint private data from the inode structure */
1428
1429  fs = vp->originMount->data;
1430  DEBUGASSERT(fs != NULL);
1431
1432  tmp = (struct fs_tmpfsdir_s *)malloc(sizeof(struct fs_tmpfsdir_s));
1433  if (!tmp)
1434    {
1435      return -ENOSPC;
1436    }
1437
1438  /* Get exclusive access to the file system */
1439
1440  tmpfs_lock(fs);
1441
1442  /* Find the directory object associated with this relative path.
1443   * If successful, this action will lock both the parent directory and
1444   * the file object, adding one to the reference count of both.
1445   * In the event that -ENOENT, there will still be a reference and
1446   * lock on the returned directory.
1447   */
1448
1449  if (vp->data != NULL)
1450    {
1451      tdo = (struct tmpfs_directory_s *)vp->data;
1452    }
1453  else
1454    {
1455      tdo = (struct tmpfs_directory_s *)fs->tfs_root.tde_object;
1456    }
1457
1458  if (tdo == NULL)
1459    {
1460      free(tmp);
1461      tmpfs_unlock(fs);
1462      return -EINTR;
1463    }
1464  tmpfs_lock_directory(tdo);
1465  tmp->tf_tdo   = tdo;
1466  tmp->tf_index = 0;
1467  dir->u.fs_dir = (fs_dir_s)tmp;
1468  tdo->tdo_count++;
1469  tdo->tdo_refs++;
1470  tmpfs_unlock_directory(tdo);
1471
1472  /* Release the lock on the file system and return the result */
1473
1474  tmpfs_unlock(fs);
1475  return ret;
1476}
1477
1478/****************************************************************************
1479 * Name: tmpfs_closedir
1480 ****************************************************************************/
1481
1482int tmpfs_closedir(struct Vnode *vp, struct fs_dirent_s *dir)
1483{
1484  struct tmpfs_directory_s *tdo;
1485  struct fs_tmpfsdir_s *tmp;
1486
1487  DEBUGASSERT(vp != NULL && dir != NULL);
1488
1489  /* Get the directory structure from the dir argument */
1490
1491  tmp = (struct fs_tmpfsdir_s *)dir->u.fs_dir;
1492  if (tmp == NULL)
1493    {
1494      return -ENOENT;
1495    }
1496  tdo = tmp->tf_tdo;
1497  DEBUGASSERT(tdo != NULL);
1498
1499  /* Decrement the reference count on the directory object */
1500
1501  tmpfs_lock_directory(tdo);
1502  if (tdo->tdo_count == 1)
1503    {
1504      LOS_DL_LIST *node = tdo->tdo_entry.pstNext;
1505      struct tmpfs_dirent_s *tde;
1506      while (node != &tdo->tdo_entry)
1507        {
1508          tde = (struct tmpfs_dirent_s *)node;
1509          node = node->pstNext;
1510          if (tde->tde_inuse == false)
1511            {
1512              LOS_ListDelete(&tde->tde_node);
1513              kmm_free(tde);
1514            }
1515        }
1516    }
1517  if (tdo->tdo_refs > 0)
1518    {
1519      tdo->tdo_refs--;
1520    }
1521  if (tdo->tdo_count > 0)
1522    {
1523      tdo->tdo_count--;
1524    }
1525  tmpfs_unlock_directory(tdo);
1526
1527  free(tmp);
1528
1529  return OK;
1530}
1531
1532/****************************************************************************
1533 * Name: tmpfs_readdir
1534 ****************************************************************************/
1535
1536int tmpfs_readdir(struct Vnode *vp, struct fs_dirent_s *dir)
1537{
1538  struct tmpfs_directory_s *tdo;
1539  unsigned int index;
1540  int ret;
1541  struct fs_tmpfsdir_s *tmp;
1542  LOS_DL_LIST *node;
1543  struct tmpfs_dirent_s *tde;
1544
1545  DEBUGASSERT(vp != NULL && dir != NULL);
1546
1547  /* Get the directory structure from the dir argument and lock it */
1548
1549  tmp = (struct fs_tmpfsdir_s *)dir->u.fs_dir;
1550  if (tmp == NULL)
1551    {
1552      return -ENOENT;
1553    }
1554
1555  tdo = tmp->tf_tdo;
1556  if (tdo == NULL)
1557    {
1558      return -ENOENT;
1559    }
1560
1561  tmpfs_lock_directory(tdo);
1562
1563  /* Have we reached the end of the directory? */
1564
1565  index = tmp->tf_index;
1566  node = tdo->tdo_entry.pstNext;
1567  while (node != &tdo->tdo_entry && index != 0)
1568    {
1569       node = node->pstNext;
1570       index--;
1571    }
1572
1573  while (node != &tdo->tdo_entry)
1574    {
1575      tde = (struct tmpfs_dirent_s *)node;
1576      tmp->tf_index++;
1577      if (tde->tde_inuse == true)
1578       {
1579         break;
1580       }
1581       node = node->pstNext;
1582    }
1583
1584  if (node == &tdo->tdo_entry)
1585    {
1586      /* We signal the end of the directory by returning the special error:
1587       * -ENOENT
1588       */
1589
1590      PRINT_INFO("End of directory\n");
1591      ret = -ENOENT;
1592    }
1593  else
1594    {
1595      struct tmpfs_object_s *to;
1596
1597      /* Does this entry refer to a file or a directory object? */
1598
1599      to  = tde->tde_object;
1600      DEBUGASSERT(to != NULL);
1601
1602      if (to->to_type == TMPFS_DIRECTORY)
1603        {
1604          /* A directory */
1605
1606           dir->fd_dir[0].d_type = DT_DIR;
1607        }
1608      else /* to->to_type == TMPFS_REGULAR) */
1609        {
1610          /* A regular file */
1611
1612           dir->fd_dir[0].d_type = DT_REG;
1613        }
1614
1615      /* Copy the entry name */
1616
1617      (void)strncpy_s(dir->fd_dir[0].d_name, NAME_MAX + 1, tde->tde_name, NAME_MAX);
1618
1619      dir->fd_position++;
1620      dir->fd_dir[0].d_off = dir->fd_position;
1621      dir->fd_dir[0].d_reclen = (uint16_t)sizeof(struct dirent);
1622
1623      ret = 1; // 1 means current file num is 1
1624    }
1625
1626  tmpfs_unlock_directory(tdo);
1627  return ret;
1628}
1629
1630/****************************************************************************
1631 * Name: tmpfs_rewinddir
1632 ****************************************************************************/
1633
1634int tmpfs_rewinddir(struct Vnode *vp, struct fs_dirent_s *dir)
1635{
1636  struct fs_tmpfsdir_s *tmp;
1637  PRINT_DEBUG("vp: %p dir: %p\n",  vp, dir);
1638  DEBUGASSERT(vp != NULL && dir != NULL);
1639  tmp = (struct fs_tmpfsdir_s *)dir->u.fs_dir;
1640
1641  /* Set the readdir index to zero */
1642
1643  tmp->tf_index = 0;
1644  return OK;
1645}
1646
1647int tmpfs_truncate(struct Vnode *vp, off_t len)
1648{
1649  struct tmpfs_file_s *tfo = NULL;
1650
1651  tfo = vp->data;
1652  tfo->tfo_size = 0;
1653
1654  if (tfo->tfo_data)
1655    {
1656      free(tfo->tfo_data);
1657    }
1658
1659  return OK;
1660}
1661
1662
1663/****************************************************************************
1664 * Name: tmpfs_mount
1665 ****************************************************************************/
1666
1667int tmpfs_mount(struct Mount *mnt, struct Vnode *device, const void *data)
1668{
1669  struct tmpfs_directory_s *tdo;
1670  struct tmpfs_s *fs = &tmpfs_superblock;
1671  struct Vnode *vp = NULL;
1672  int ret;
1673
1674  DEBUGASSERT(device == NULL);
1675
1676  if (fs->tfs_root.tde_object != NULL)
1677    {
1678      return -EPERM;
1679    }
1680
1681  /* Create a root file system.  This is like a single directory entry in
1682   * the file system structure.
1683   */
1684
1685  tdo = tmpfs_alloc_directory();
1686  if (tdo == NULL)
1687    {
1688      return -ENOSPC;
1689    }
1690
1691  LOS_ListInit(&fs->tfs_root.tde_node);
1692  fs->tfs_root.tde_object = (struct tmpfs_object_s *)tdo;
1693  fs->tfs_root.tde_name   = NULL;
1694
1695  /* Set up the backward link (to support reallocation) */
1696
1697  tdo->tdo_dirent         = &fs->tfs_root;
1698
1699  /* Initialize the file system state */
1700
1701  fs->tfs_exclsem.ts_holder = TMPFS_NO_HOLDER;
1702  fs->tfs_exclsem.ts_count  = 0;
1703  sem_init(&fs->tfs_exclsem.ts_sem, 0, 1);
1704
1705  /* Return the new file system handle */
1706
1707  spin_lock_init(&tmpfs_alloc_unit_lock);
1708  is_tmpfs_lock_init = true;
1709
1710  ret = VnodeAlloc(&tmpfs_vops, &vp);
1711  if (ret != 0)
1712    {
1713      ret = ENOMEM;
1714      goto ERROR_WITH_FSWIN;
1715    }
1716
1717  tdo->mode = mnt->vnodeBeCovered->mode;
1718  tdo->gid = mnt->vnodeBeCovered->gid;
1719  tdo->uid = mnt->vnodeBeCovered->uid;
1720  vp->originMount = mnt;
1721  vp->fop = &tmpfs_fops;
1722  vp->type = VNODE_TYPE_DIR;
1723  vp->data = NULL;
1724  vp->mode = tdo->mode;
1725  vp->gid = tdo->gid;
1726  vp->uid = tdo->uid;
1727  mnt->data = fs;
1728  mnt->vnodeCovered = vp;
1729
1730  return OK;
1731
1732ERROR_WITH_FSWIN:
1733  return ret;
1734}
1735
1736/****************************************************************************
1737 * Name: tmpfs_unmount
1738 ****************************************************************************/
1739
1740int tmpfs_unmount(struct Mount *mnt, struct Vnode **blkdriver)
1741{
1742  struct tmpfs_s *fs = (struct tmpfs_s *)mnt->data;
1743  struct tmpfs_directory_s *tdo;
1744  int ret = 0;
1745
1746  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
1747
1748  /* Lock the file system */
1749
1750  tmpfs_lock(fs);
1751
1752  tdo = (struct tmpfs_directory_s *)fs->tfs_root.tde_object;
1753  if (tdo == NULL)
1754    {
1755      ret = -EINVAL;
1756      goto errout_with_objects;
1757    }
1758
1759  if (tdo->tdo_nentries > 0 || tdo->tdo_refs > 1)
1760    {
1761      ret = -EBUSY;
1762      goto errout_with_objects;
1763    }
1764
1765  /* Now we can destroy the root file system and the file system itself. */
1766
1767  sem_destroy(&tdo->tdo_exclsem.ts_sem);
1768  kmm_free(tdo);
1769
1770  sem_destroy(&fs->tfs_exclsem.ts_sem);
1771  fs->tfs_root.tde_object = NULL;
1772
1773  tmpfs_unlock(fs);
1774  is_tmpfs_lock_init = false;
1775  return ret;
1776
1777errout_with_objects:
1778  tmpfs_unlock(fs);
1779  return ret;
1780}
1781
1782
1783int tmpfs_lookup(struct Vnode *parent, const char *relPath, int len, struct Vnode **vpp)
1784{
1785  // 1. when first time create file, lookup fail, then call tmpfs_create.
1786  // 2. when  ls, lookup will success to show.
1787  // 3. when cd, lookup success.
1788  struct tmpfs_object_s *to;
1789  struct tmpfs_s *fs;
1790  struct tmpfs_dirent_s *tde = NULL;
1791  struct tmpfs_directory_s *parent_tdo;
1792
1793  struct Vnode *vp = NULL;
1794  int ret = 0;
1795  char filename[len + 1];
1796  ret = memcpy_s(filename, (len + 1), relPath, len);
1797  if (ret != 0)
1798    {
1799        ret = -ENOMEM;
1800        goto errout;
1801    }
1802  filename[len] = '\0';
1803
1804  fs = parent->originMount->data;
1805  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
1806
1807  tmpfs_lock(fs);
1808
1809  parent_tdo = (struct tmpfs_directory_s *)(parent->data);
1810
1811  if (parent_tdo == NULL)
1812    {
1813      // if parent_tdo don't exist, find file in root.
1814      ret = tmpfs_find_object(fs, filename, &to, NULL);
1815      if (ret < 0)
1816        {
1817          goto errout_with_lock;
1818        }
1819    }
1820  else
1821    {
1822      if (parent_tdo->tdo_type != TMPFS_DIRECTORY)
1823        {
1824          ret = -ENOENT;
1825          goto errout_with_lock;
1826        }
1827      // if parent_tdo exist£¬search for the relationship between parent_tdo and the current dirname.
1828      tde = tmpfs_find_dirent(parent_tdo, filename);
1829      if (tde == NULL)
1830        {
1831          ret = -ENOENT;
1832          goto errout_with_lock;
1833        }
1834      to = tde->tde_object;
1835    }
1836
1837  if (to == NULL)
1838    {
1839      ret = -ENOENT;
1840      goto errout_with_lock;
1841    }
1842  tmpfs_lock_object(to);
1843  to->to_refs++;
1844
1845  (void)VfsHashGet(parent->originMount, (uint32_t)to, &vp, NULL, NULL);
1846  if (vp == NULL)
1847    {
1848      ret = VnodeAlloc(&tmpfs_vops, &vp);
1849      if (ret != 0)
1850        {
1851          PRINTK("%s-%d \n", __FUNCTION__, __LINE__);
1852          goto errout_with_objects;
1853        }
1854
1855      vp->vop = parent->vop;
1856      vp->fop = parent->fop;
1857      vp->data = to;
1858      vp->originMount = parent->originMount;
1859      vp->type = to->to_type == TMPFS_REGULAR ? VNODE_TYPE_REG : VNODE_TYPE_DIR;
1860      vp->mode = to->mode;
1861      vp->gid = to->gid;
1862      vp->uid = to->uid;
1863
1864      ret = VfsHashInsert(vp, (uint32_t)to);
1865    }
1866  vp->parent = parent;
1867
1868  *vpp = vp;
1869
1870  tmpfs_release_lockedobject(to);
1871  tmpfs_unlock(fs);
1872
1873  return 0;
1874
1875errout_with_objects:
1876  tmpfs_release_lockedobject(to);
1877errout_with_lock:
1878  tmpfs_unlock(fs);
1879errout:
1880  return ret;
1881}
1882
1883int tmpfs_reclaim(struct Vnode *vp)
1884{
1885    vp->data = NULL;
1886    return 0;
1887}
1888
1889/****************************************************************************
1890 * Name: tmpfs_statfs
1891 ****************************************************************************/
1892
1893int tmpfs_statfs(struct Mount *mp, struct statfs *sbp)
1894{
1895  (void)memset_s(sbp, sizeof(struct statfs), 0, sizeof(struct statfs));
1896
1897  sbp->f_type = TMPFS_MAGIC;
1898  sbp->f_flags = mp->mountFlags;
1899
1900  return OK;
1901}
1902
1903/****************************************************************************
1904 * Name: tmpfs_unlink
1905 ****************************************************************************/
1906
1907int tmpfs_unlink(struct Vnode *parent, struct Vnode *node, const char *relpath)
1908{
1909  struct tmpfs_s *fs;
1910  struct tmpfs_directory_s *parent_dir;
1911  struct tmpfs_file_s *tfo = NULL;
1912  int ret;
1913
1914  PRINT_INFO("mountpt: %p node: %p relpath: %s\n", parent, node, relpath);
1915  DEBUGASSERT(parent != NULL && node != NULL && relpath != NULL);
1916
1917  if (strlen(relpath) == 0)
1918    {
1919      return -EISDIR;
1920    }
1921
1922  /* Get the file system structure from the inode reference. */
1923  if (node->originMount == NULL)
1924    {
1925      return -EISDIR;
1926    }
1927
1928  fs = node->originMount->data;
1929  if (fs == NULL)
1930    {
1931      return -EISDIR;
1932    }
1933
1934  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
1935
1936  /* Get exclusive access to the file system */
1937
1938  tmpfs_lock(fs);
1939
1940  /* Find the file object and parent directory associated with this relative
1941   * path.  If successful, tmpfs_find_file will lock both the file object
1942   * and the parent directory and take one reference count on each.
1943   */
1944
1945  parent_dir = (struct tmpfs_directory_s *)(parent->data);
1946  if (parent_dir == NULL)
1947    {
1948      ret = tmpfs_find_file(fs, relpath, &tfo, &parent_dir);
1949      if (ret < 0)
1950        {
1951          goto errout_with_lock;
1952        }
1953    }
1954  else
1955    {
1956      tfo = (struct tmpfs_file_s *)node->data;
1957    }
1958
1959  if (tfo == NULL || parent_dir == NULL)
1960    {
1961      ret = -EISDIR;
1962      goto errout_with_lock;
1963    }
1964  DEBUGASSERT(tfo != NULL);
1965  tmpfs_lock_directory(parent_dir);
1966  tmpfs_lock_file(tfo);
1967
1968  /* Remove the file from parent directory */
1969  ret = tmpfs_remove_dirent(parent_dir, (struct tmpfs_object_s *)tfo);
1970  if (ret < 0)
1971    {
1972      goto errout_with_objects;
1973    }
1974
1975  /* If the reference count is not one, then just mark the file as
1976   * unlinked
1977   */
1978
1979  if (tfo->tfo_refs > 1)
1980    {
1981      /* Make the file object as unlinked */
1982
1983      tfo->tfo_flags |= TFO_FLAG_UNLINKED;
1984
1985      /* Release the reference count on the file object */
1986
1987      tfo->tfo_refs--;
1988      tmpfs_unlock_file(tfo);
1989    }
1990
1991  /* Otherwise we can free the object now */
1992
1993  else
1994    {
1995      sem_destroy(&tfo->tfo_exclsem.ts_sem);
1996      kmm_free(tfo->tfo_data);
1997      kmm_free(tfo);
1998      node->data = NULL;
1999    }
2000
2001  /* Release the reference and lock on the parent directory */
2002
2003  if (parent_dir->tdo_refs > 0)
2004    {
2005      parent_dir->tdo_refs--;
2006    }
2007  tmpfs_unlock_directory(parent_dir);
2008  tmpfs_unlock(fs);
2009
2010  return OK;
2011
2012errout_with_objects:
2013  tmpfs_release_lockedfile(tfo);
2014
2015  if (parent_dir->tdo_refs > 0)
2016    {
2017      parent_dir->tdo_refs--;
2018    }
2019
2020  tmpfs_unlock_directory(parent_dir);
2021
2022errout_with_lock:
2023  tmpfs_unlock(fs);
2024  return ret;
2025}
2026
2027/****************************************************************************
2028 * Name: tmpfs_mkdir
2029 ****************************************************************************/
2030
2031int tmpfs_mkdir(struct Vnode *parent, const char *relpath, mode_t mode, struct Vnode **vpp)
2032{
2033  struct tmpfs_s *fs;
2034  struct Vnode *vp = NULL;
2035  struct tmpfs_directory_s *tdo;
2036  struct tmpfs_directory_s *parent_tdo = NULL;
2037  int ret;
2038
2039  DEBUGASSERT(parent != NULL && relpath != NULL);
2040
2041  if (strlen(relpath) == 0)
2042    {
2043      return -EEXIST;
2044    }
2045
2046  /* Get the file system structure from the inode reference. */
2047
2048  fs = parent->originMount->data;
2049  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
2050
2051  /* Get exclusive access to the file system */
2052
2053  tmpfs_lock(fs);
2054
2055  if (parent->data != NULL)
2056    {
2057      parent_tdo = (struct tmpfs_directory_s *)(parent->data);
2058    }
2059  /* Create the directory. */
2060  ret = tmpfs_create_directory(fs, relpath, parent_tdo, &tdo);
2061  if (ret != OK)
2062    {
2063      goto errout_with_lock;
2064    }
2065
2066  ret = VnodeAlloc(&tmpfs_vops, &vp);
2067  if (ret != 0)
2068    {
2069      goto errout_with_lock;
2070    }
2071
2072  tdo->mode = mode;
2073  vp->parent = parent;
2074  vp->vop = parent->vop;
2075  vp->fop = parent->fop;
2076  vp->data = tdo;
2077  vp->originMount = parent->originMount;
2078  vp->type = VNODE_TYPE_DIR;
2079  vp->mode = tdo->mode;
2080  vp->gid = tdo->gid;
2081  vp->uid = tdo->uid;
2082
2083  ret = VfsHashInsert(vp, (uint32_t)tdo);
2084  *vpp = vp;
2085
2086errout_with_lock:
2087  tmpfs_unlock(fs);
2088  return ret;
2089}
2090
2091/****************************************************************************
2092 * Name: tmpfs_rmdir
2093 ****************************************************************************/
2094
2095int tmpfs_rmdir(struct Vnode *parent, struct Vnode *target, const char *dirname)
2096{
2097  struct tmpfs_s *fs;
2098  struct tmpfs_directory_s *parent_dir;
2099  struct tmpfs_directory_s *tdo;
2100  int ret = 0;
2101
2102  DEBUGASSERT(parent != NULL && target != NULL && dirname != NULL);
2103
2104  /* Get the file system structure from the inode reference. */
2105  fs = parent->originMount->data;
2106  if (fs == NULL)
2107    {
2108      return -EISDIR;
2109    }
2110  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
2111
2112  /* Get exclusive access to the file system */
2113
2114  tmpfs_lock(fs);
2115
2116  /* Find the directory object and parent directory associated with this
2117   * relative path.  If successful, tmpfs_find_file will lock both the
2118   * directory object and the parent directory and take one reference count
2119   * on each.
2120   */
2121  parent_dir = (struct tmpfs_directory_s *)(parent->data);
2122  if (parent_dir == NULL)
2123    {
2124      ret = tmpfs_find_directory(fs, dirname, &tdo, &parent_dir);
2125      if (ret < 0)
2126        {
2127          goto errout_with_lock;
2128        }
2129    }
2130  else
2131    {
2132      tdo = (struct tmpfs_directory_s *)target->data;
2133    }
2134
2135  if (tdo == NULL || tdo->tdo_type != TMPFS_DIRECTORY)
2136    {
2137      ret = -EISDIR;
2138      goto errout_with_lock;
2139    }
2140  tmpfs_lock_directory(parent_dir);
2141
2142  /* Is the directory empty?  We cannot remove directories that still
2143   * contain references to file system objects.  No can we remove the
2144   * directory if there are outstanding references on it (other than
2145   * our reference).
2146   */
2147
2148  if (tdo->tdo_nentries > 0 || tdo->tdo_refs > 1)
2149    {
2150      ret = -EBUSY;
2151      goto errout_with_objects;
2152    }
2153  /* Remove the directory from parent directory */
2154  ret = tmpfs_remove_dirent(parent_dir, (struct tmpfs_object_s *)tdo);
2155  if (ret < 0)
2156    {
2157      goto errout_with_objects;
2158    }
2159
2160  /* Free the directory object */
2161
2162  sem_destroy(&tdo->tdo_exclsem.ts_sem);
2163  kmm_free(tdo);
2164  target->data = NULL;
2165
2166  /* Release the reference and lock on the parent directory */
2167
2168  if (parent_dir->tdo_refs > 0)
2169    {
2170      parent_dir->tdo_refs--;
2171    }
2172
2173  tmpfs_unlock_directory(parent_dir);
2174  tmpfs_unlock(fs);
2175
2176  return OK;
2177
2178errout_with_objects:
2179  if (tdo->tdo_refs > 0)
2180    {
2181      tdo->tdo_refs--;
2182    }
2183  tmpfs_unlock_directory(tdo);
2184
2185  if (parent_dir->tdo_refs > 0)
2186    {
2187      parent_dir->tdo_refs--;
2188    }
2189  tmpfs_unlock_directory(parent_dir);
2190
2191errout_with_lock:
2192  tmpfs_unlock(fs);
2193  return ret;
2194}
2195
2196/****************************************************************************
2197 * Name: tmpfs_rename
2198 ****************************************************************************/
2199
2200int tmpfs_rename(struct Vnode *oldVnode, struct Vnode *newParent, const char *oldname, const char *newname)
2201{
2202  struct tmpfs_directory_s *oldparent;
2203  struct tmpfs_directory_s *newparent_tdo;
2204  struct tmpfs_object_s *old_to;
2205  struct tmpfs_dirent_s *tde;
2206  struct tmpfs_directory_s *tdo;
2207  struct tmpfs_file_s *tfo;
2208  struct tmpfs_s *fs;
2209  struct tmpfs_s *new_fs;
2210  struct Vnode *old_parent_vnode;
2211
2212  char *copy;
2213  int ret = 0;
2214  unsigned int oldrelpath_len, newrelpath_len, cmp_namelen;
2215
2216  oldrelpath_len = strlen(oldname);
2217  newrelpath_len = strlen(newname);
2218
2219  cmp_namelen = (oldrelpath_len <= newrelpath_len) ? oldrelpath_len : newrelpath_len;
2220  if (!cmp_namelen || ((!strncmp(oldname, newname, cmp_namelen)) &&
2221           (oldname[cmp_namelen] == '/' ||
2222            newname[cmp_namelen] == '/')))
2223    {
2224      return -EPERM;
2225    }
2226
2227  /* Get the file system structure from the inode reference. */
2228  if (oldVnode->parent == NULL)
2229    {
2230      return -EPERM;
2231    }
2232
2233  fs = oldVnode->parent->originMount->data;
2234  if (fs == NULL)
2235    {
2236      return -EPERM;
2237    }
2238
2239  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
2240
2241  /* Duplicate the newpath variable so that we can modify it */
2242
2243  copy = strdup(newname);
2244  if (copy == NULL)
2245    {
2246      return -ENOSPC;
2247    }
2248
2249  /* Get exclusive access to the file system */
2250
2251  tmpfs_lock(fs);
2252
2253  /* Separate the new path into the new file name and the path to the new
2254   * parent directory.
2255   */
2256  newparent_tdo = (struct tmpfs_directory_s *)(newParent->data);
2257  if (newparent_tdo == NULL)
2258    {
2259      new_fs = newParent->originMount->data;
2260      newparent_tdo = (struct tmpfs_directory_s *)new_fs->tfs_root.tde_object;
2261      if (newparent_tdo == NULL)
2262        {
2263          ret = -ENOTEMPTY;
2264          goto errout_with_lock;
2265        }
2266      tmpfs_lock_directory(newparent_tdo);
2267      newparent_tdo->tdo_refs++;
2268    }
2269
2270  /* Find the old object at oldpath.  If successful, tmpfs_find_object()
2271   * will lock both the object and the parent directory and will increment
2272   * the reference count on both.
2273   */
2274  old_parent_vnode = oldVnode->parent;
2275  oldparent = (struct tmpfs_directory_s *)(old_parent_vnode->data);
2276  old_to = (struct tmpfs_object_s *)oldVnode->data;
2277
2278  if (oldparent == NULL)
2279    {
2280      oldparent = (struct tmpfs_directory_s *)fs->tfs_root.tde_object;
2281      if (oldparent == NULL || old_to == NULL)
2282        {
2283          ret = -ENOTEMPTY;
2284          goto errout_with_newparent;
2285        }
2286    }
2287
2288  tmpfs_lock_directory(oldparent);
2289  tmpfs_lock_object(old_to);
2290  oldparent->tdo_refs++;
2291  old_to->to_refs++;
2292  tde = tmpfs_find_dirent(newparent_tdo, copy);
2293  if (tde != NULL)
2294    {
2295      struct tmpfs_object_s *new_to = tde->tde_object;
2296
2297      /* Cannot rename a directory to a noempty directory */
2298
2299      if (tde->tde_object->to_type == TMPFS_DIRECTORY)
2300        {
2301          tdo = (struct tmpfs_directory_s *)new_to;
2302          if (tdo->tdo_nentries != 0)
2303            {
2304              ret = -ENOTEMPTY;
2305              goto errout_with_oldparent;
2306            }
2307        }
2308
2309      /* Null rename, just return */
2310
2311      if (old_to == new_to)
2312        {
2313          ret = ENOERR;
2314          goto errout_with_oldparent;
2315        }
2316
2317      /* Check that we are renaming like-for-like */
2318
2319      if (old_to->to_type == TMPFS_REGULAR && new_to->to_type == TMPFS_DIRECTORY)
2320        {
2321          ret = -EISDIR;
2322          goto errout_with_oldparent;
2323        }
2324
2325      if (old_to->to_type == TMPFS_DIRECTORY && new_to->to_type == TMPFS_REGULAR)
2326        {
2327          ret = -ENOTDIR;
2328          goto errout_with_oldparent;
2329        }
2330
2331      /* Now delete the destination directory entry */
2332
2333      ret = tmpfs_remove_dirent(newparent_tdo, new_to);
2334      if (ret < 0)
2335        {
2336          goto errout_with_oldparent;
2337        }
2338
2339      if (new_to->to_type == TMPFS_DIRECTORY)
2340        {
2341          (void)sem_destroy(&new_to->to_exclsem.ts_sem);
2342          kmm_free(new_to);
2343        }
2344      else
2345        {
2346          tfo = (struct tmpfs_file_s *)new_to;
2347          if (new_to->to_refs > 0)
2348            {
2349              /* Make the file object as unlinked */
2350
2351              tfo->tfo_flags |= TFO_FLAG_UNLINKED;
2352            }
2353
2354          /* Otherwise we can free the object now */
2355
2356          else
2357            {
2358              (void)sem_destroy(&tfo->tfo_exclsem.ts_sem);
2359              kmm_free(tfo->tfo_data);
2360              kmm_free(tfo);
2361            }
2362        }
2363    }
2364
2365  /* Remove the entry from the parent directory */
2366
2367  ret = tmpfs_remove_dirent(oldparent, old_to);
2368  if (ret < 0)
2369    {
2370      goto errout_with_oldparent;
2371    }
2372
2373  /* Add an entry to the new parent directory. */
2374
2375  ret = tmpfs_add_dirent(&newparent_tdo, old_to, copy);
2376  oldVnode->parent = newParent;
2377
2378errout_with_oldparent:
2379  if (oldparent == NULL)
2380    {
2381      tmpfs_unlock(fs);
2382      kmm_free(copy);
2383      return ret;
2384    }
2385  if (oldparent->tdo_refs > 0)
2386    {
2387      oldparent->tdo_refs--;
2388    }
2389  tmpfs_unlock_directory(oldparent);
2390  tmpfs_release_lockedobject(old_to);
2391
2392errout_with_newparent:
2393  if (newparent_tdo == NULL)
2394    {
2395      tmpfs_unlock(fs);
2396      kmm_free(copy);
2397      return ret;
2398    }
2399  if (newparent_tdo->tdo_refs > 0)
2400    {
2401      newparent_tdo->tdo_refs--;
2402    }
2403  tmpfs_unlock_directory(newparent_tdo);
2404
2405errout_with_lock:
2406  tmpfs_unlock(fs);
2407  kmm_free(copy);
2408  return ret;
2409}
2410
2411/****************************************************************************
2412 * Name: tmpfs_stat_common
2413 ****************************************************************************/
2414
2415static void tmpfs_stat_common(struct tmpfs_object_s *to,
2416                              struct stat *buf)
2417{
2418  size_t objsize;
2419
2420  /* Is the tmpfs object a regular file? */
2421
2422  (VOID)memset_s(buf, sizeof(struct stat), 0, sizeof(struct stat));
2423
2424  if (to->to_type == TMPFS_REGULAR)
2425    {
2426      struct tmpfs_file_s *tfo =
2427        (struct tmpfs_file_s *)to;
2428
2429      /* -rwxrwxrwx */
2430
2431      buf->st_mode = S_IRWXO | S_IRWXG | S_IRWXU | S_IFREG;
2432      buf->st_nlink = tfo->tfo_refs - 1;
2433
2434      /* Get the size of the object */
2435
2436      objsize = tfo->tfo_size;
2437    }
2438  else /* if (to->to_type == TMPFS_DIRECTORY) */
2439    {
2440      struct tmpfs_directory_s *tdo =
2441        (struct tmpfs_directory_s *)to;
2442
2443      /* drwxrwxrwx */
2444
2445      buf->st_mode = S_IRWXO | S_IRWXG | S_IRWXU | S_IFDIR;
2446      buf->st_nlink   = tdo->tdo_nentries + tdo->tdo_refs;
2447
2448      /* Get the size of the object */
2449
2450      objsize = sizeof(struct tmpfs_directory_s);
2451    }
2452
2453  /* Fake the rest of the information */
2454
2455  buf->st_size    = objsize;
2456  buf->st_blksize = 0;
2457  buf->st_blocks  = 0;
2458  buf->st_atime   = to->to_atime;
2459  buf->st_mtime   = to->to_mtime;
2460  buf->st_ctime   = to->to_ctime;
2461
2462  /* Adapt to kstat member "long tv_sec" */
2463  buf->__st_atim32.tv_sec = (long)to->to_atime;
2464  buf->__st_mtim32.tv_sec = (long)to->to_mtime;
2465  buf->__st_ctim32.tv_sec = (long)to->to_ctime;
2466
2467}
2468
2469/****************************************************************************
2470 * Name: tmpfs_stat
2471 ****************************************************************************/
2472
2473int tmpfs_stat(struct Vnode *vp, struct stat *st)
2474{
2475  struct tmpfs_s *fs;
2476  struct tmpfs_object_s *to;
2477  int ret;
2478
2479  DEBUGASSERT(vp != NULL && st != NULL);
2480  /* Get the file system structure from the inode reference. */
2481
2482  fs = vp->originMount->data;
2483  DEBUGASSERT(fs != NULL && fs->tfs_root.tde_object != NULL);
2484
2485  /* Get exclusive access to the file system */
2486
2487  tmpfs_lock(fs);
2488
2489  /* Find the tmpfs object at the relpath.  If successful,
2490   * tmpfs_find_object() will lock the object and increment the
2491   * reference count on the object.
2492   */
2493  if (vp->data != NULL)
2494    {
2495      to = (struct tmpfs_object_s *)vp->data;
2496    }
2497  else
2498    {
2499      to = fs->tfs_root.tde_object;
2500    }
2501  tmpfs_lock_object(to);
2502  to->to_refs++;
2503
2504  /* We found it... Return information about the file object in the stat
2505   * buffer.
2506   */
2507  if(to == NULL)
2508    {
2509      ret = -ENOENT;
2510      goto errout_with_fslock;
2511    }
2512  DEBUGASSERT(to != NULL);
2513  tmpfs_stat_common(to, st);
2514
2515  /* Unlock the object and return success */
2516
2517  tmpfs_release_lockedobject(to);
2518  ret = OK;
2519
2520errout_with_fslock:
2521  tmpfs_unlock(fs);
2522  return ret;
2523}
2524
2525FSMAP_ENTRY(ramfs_fsmap, "ramfs", tmpfs_operations, FALSE, FALSE);
2526
2527#endif
2528
2529