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