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