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