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