1/**************************************************************************** 2 * fs/nfs/nfs_vfsops.c 3 * 4 * Copyright (C) 2012-2013, 2015, 2017-2018 Gregory Nutt. All rights reserved. 5 * Copyright (C) 2012 Jose Pablo Rojas Vargas. All rights reserved. 6 * Author: Jose Pablo Rojas Vargas <jrojas@nx-engineering.com> 7 * Gregory Nutt <gnutt@nuttx.org> 8 * 9 * Leveraged from OpenBSD: 10 * 11 * Copyright (c) 1989, 1993, 1995 12 * The Regents of the University of California. All rights reserved. 13 * 14 * This code is derived from software contributed to Berkeley by 15 * Rick Macklem at The University of Guelph. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 3. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 ****************************************************************************/ 43 44/**************************************************************************** 45 * Included Files 46 ****************************************************************************/ 47 48#include <sys/mount.h> 49#include <sys/socket.h> 50#include <sys/statfs.h> 51#include <sys/stat.h> 52#include <stdlib.h> 53#include <string.h> 54#include <fcntl.h> 55#include <semaphore.h> 56#include <assert.h> 57#include <errno.h> 58#include <pthread.h> 59#include <unistd.h> 60#include "lwip/opt.h" 61#include "lwip/sockets.h" 62#include "vfs_config.h" 63#include "dirent.h" 64#include "fs/fs.h" 65#include "fs/dirent_fs.h" 66#include "nfs.h" 67#include "nfs_node.h" 68#include "xdr_subs.h" 69#include "los_tables.h" 70#include "vnode.h" 71#include "los_vm_filemap.h" 72#include "user_copy.h" 73 74/**************************************************************************** 75 * Pre-processor Definitions 76 ****************************************************************************/ 77/**************************************************************************** 78 * Public Data 79 ****************************************************************************/ 80 81uint32_t nfs_true; 82uint32_t nfs_false; 83uint32_t nfs_xdrneg1; 84NFSMOUNT_HOOK g_NFSMOUNT_HOOK = (NFSMOUNT_HOOK)(UINTPTR)NULL; 85 86#ifdef CONFIG_NFS_STATISTICS 87struct nfsstats nfsstats; 88#endif 89 90#define USE_GUARDED_CREATE 1 91 92#ifdef LOSCFG_FS_NFS 93/**************************************************************************** 94 * Private Type Definitions 95 ****************************************************************************/ 96 97#define NFS_DIR_ENTRY_MALLOC(entry) \ 98 do \ 99 { \ 100 entry = (struct entry3 *)malloc(sizeof(struct entry3)); \ 101 if (entry == NULL) \ 102 { \ 103 nfs_debug_info("malloc failed\n"); \ 104 error = ENOMEM; \ 105 goto errout_with_memory; \ 106 } \ 107 (void)memset_s(entry, sizeof(struct entry3), 0, sizeof(struct entry3)); \ 108 } \ 109 while (0) 110 111#define NFS_DIR_ENTRY_FREE(entry) \ 112 do \ 113 { \ 114 free(entry->contents); \ 115 entry->contents = NULL; \ 116 free(entry); \ 117 entry = NULL; \ 118 } \ 119 while (0) 120 121#define FILENAME_MAX_LEN 50 122struct MountOps nfs_mount_operations; 123struct VnodeOps nfs_vops; 124struct file_operations_vfs nfs_fops; 125struct nfs_statinfo_s 126{ 127 uint16_t ns_mode; /* File access mode */ 128 uint8_t ns_type; /* File type */ 129 uint64_t ns_size; /* File size */ 130 time_t ns_atime; /* Time of last access */ 131 time_t ns_mtime; /* Time of last modification */ 132 time_t ns_ctime; /* Time of last status change */ 133}; 134extern void nfs_stat_common(struct nfs_statinfo_s *info, struct stat *buf); 135 136static mode_t type_to_mode(int type, mode_t permission) 137{ 138 switch (type) 139 { 140 case VNODE_TYPE_DIR: 141 return permission | S_IFDIR; 142 case VNODE_TYPE_REG: 143 return permission | S_IFREG; 144 case VNODE_TYPE_BLK: 145 return permission | S_IFBLK; 146 case VNODE_TYPE_CHR: 147 return permission | S_IFCHR; 148 case VNODE_TYPE_FIFO: 149 return permission | S_IFIFO; 150 default: 151 break; 152 } 153 return permission; 154} 155 156static int nfs_2_vfs(int result) 157{ 158 int status; 159 160 if ((result < NFS_OK) || (result > NFSERR_NOTEMPTY)) 161 { 162 return result; 163 } 164 165 /* Nfs errno to Libc errno */ 166 switch (result) 167 { 168 case NFSERR_NAMETOL: 169 status = ENAMETOOLONG; 170 break; 171 case NFSERR_NOTEMPTY: 172 status = ENOTEMPTY; 173 break; 174 default: 175 status = result; 176 break; 177 } 178 179 return status; 180} 181 182/**************************************************************************** 183 * Name: nfs_fileupdate 184 * 185 * Description: 186 * This is to update the file attributes like size, type. This sends a LOOKUP msg of nfs 187 * to get latest file attributes. 188 * 189 * Returned Value: 190 * 0 on success; a positive errno value on failure. 191 * 192 ****************************************************************************/ 193static int nfs_fileupdate(struct nfsmount *nmp, char *filename, 194 struct file_handle *parent_fhandle, struct nfsnode *np) 195{ 196 struct file_handle fhandle; 197 int error; 198 struct nfs_fattr fattr; 199 200 /* Find the NFS node associate with the path */ 201 202 fhandle.length = parent_fhandle->length; 203 (void)memcpy_s(&(fhandle.handle), fhandle.length, &(parent_fhandle->handle), parent_fhandle->length); 204 error = nfs_lookup(nmp, filename, &fhandle, &fattr, NULL); 205 206 if (error != OK) 207 { 208 nfs_debug_error("nfs_lookup failed returned: %d\n", error); 209 return error; 210 } 211 212 /* Update the file handle */ 213 214 error = memcpy_s(&(np->n_fhandle), NFSX_V3FHMAX, &(fhandle.handle), fhandle.length); 215 if (error != EOK) 216 { 217 return ENOBUFS; 218 } 219 220 np->n_fhsize = fhandle.length; 221 222 /* Save the file attributes */ 223 224 nfs_attrupdate(np, &fattr); 225 226 return OK; 227} 228 229int vfs_nfs_reclaim(struct Vnode *node) 230{ 231 struct nfsnode *prev = NULL; 232 struct nfsnode *curr = NULL; 233 struct nfsmount *nmp = NULL; 234 struct nfsnode *np = NULL; 235 if (node->data == NULL) 236 { 237 return OK; 238 } 239 nmp = (struct nfsmount *)(node->originMount->data); 240 nfs_mux_take(nmp); 241 np = (struct nfsnode*)(node->data); 242 int ret; 243 244 if (np->n_crefs > 1) 245 { 246 np->n_crefs--; 247 ret = OK; 248 } 249 250 /* There are no more references to the file structure. Now we need to 251 * free up all resources associated with the open file. 252 * 253 * First, find our file structure in the list of file structures 254 * containted in the mount structure. 255 */ 256 257 else 258 { 259 /* Assume file structure will not be found. This should never happen. */ 260 261 ret = -EINVAL; 262 263 for (prev = NULL, curr = nmp->nm_head; 264 curr; 265 prev = curr, curr = curr->n_next) 266 { 267 /* Check if this node is ours */ 268 269 if (np == curr) 270 { 271 /* Yes.. remove it from the list of file structures */ 272 273 if (prev) 274 { 275 /* Remove from mid-list */ 276 277 prev->n_next = np->n_next; 278 } 279 else 280 { 281 /* Remove from the head of the list */ 282 283 nmp->nm_head = np->n_next; 284 } 285 286 /* Then deallocate the file structure and return success */ 287 288 free(np->n_name); 289 free(np); 290 ret = OK; 291 break; 292 } 293 } 294 } 295 296 nfs_mux_release(nmp); 297 return ret; 298} 299 300static int vfs_nfs_stat_internal(struct nfsmount *nmp, struct nfsnode *nfs_node) 301{ 302 int ret; 303 struct timespec ts; 304 struct rpc_call_fs attr_call; 305 struct rpc_reply_getattr attr_reply; 306 attr_call.fs.fsroot.length = txdr_unsigned(nfs_node->n_fhsize); 307 memcpy_s(&(attr_call.fs.fsroot.handle), sizeof(nfsfh_t), &(nfs_node->n_fhandle), sizeof(nfsfh_t)); 308 ret = nfs_request(nmp, NFSPROC_GETATTR, &attr_call, 309 sizeof(struct file_handle), &attr_reply, 310 sizeof(struct rpc_reply_getattr)); 311 if (ret != OK) 312 { 313 return ret; 314 } 315 /* Extract the file mode, file type, and file size. */ 316 317 nfs_node->n_mode = fxdr_unsigned(uint16_t, attr_reply.attr.fa_mode); 318 nfs_node->n_type = fxdr_unsigned(uint8_t, attr_reply.attr.fa_type); 319 nfs_node->n_size = fxdr_hyper(&attr_reply.attr.fa_size); 320 321 /* Extract time values as type time_t in units of seconds */ 322 323 fxdr_nfsv3time(&attr_reply.attr.fa_mtime, &ts); 324 nfs_node->n_timestamp.tv_sec = ts.tv_sec; 325 nfs_node->n_timestamp.tv_nsec = ts.tv_nsec; 326 327 fxdr_nfsv3time(&attr_reply.attr.fa_atime, &ts); 328 nfs_node->n_atime = ts.tv_sec; 329 330 fxdr_nfsv3time(&attr_reply.attr.fa_ctime, &ts); 331 nfs_node->n_ctime = ts.tv_sec; 332 333 return OK; 334} 335 336/**************************************************************************** 337 * Name: nfs_decode_args 338 * 339 * Returned Value: 340 * None 341 * 342 ****************************************************************************/ 343 344static void nfs_decode_args(struct nfs_mount_parameters *nprmt, 345 struct nfs_args *argp) 346{ 347 int maxio; 348 349 /* Get the selected timeout value */ 350 351 if ((argp->flags & NFSMNT_TIMEO) != 0 && argp->timeo > 0) 352 { 353 uint32_t tmp = ((uint32_t)argp->timeo * NFS_HZ + 5) / 10; 354 if (tmp < NFS_MINTIMEO) 355 { 356 tmp = NFS_MINTIMEO; 357 } 358 else if (tmp > NFS_MAXTIMEO) 359 { 360 tmp = NFS_MAXTIMEO; 361 } 362 363 nprmt->timeo = tmp; 364 } 365 366 /* Get the selected retransmission count */ 367 368 if ((argp->flags & NFSMNT_RETRANS) != 0 && argp->retrans > 1) 369 { 370 if (argp->retrans < NFS_MAXREXMIT) 371 { 372 nprmt->retry = argp->retrans; 373 } 374 else 375 { 376 nprmt->retry = NFS_MAXREXMIT; 377 } 378 } 379 380 if ((argp->flags & NFSMNT_SOFT) == 0) 381 { 382 nprmt->retry = NFS_MAXREXMIT + 1; /* Past clip limit */ 383 } 384 385 /* Get the maximum amount of data that can be transferred in one packet */ 386 387 if ((argp->sotype == SOCK_DGRAM) != 0) 388 { 389 maxio = NFS_MAXDGRAMDATA; 390 } 391 else 392 { 393 nfs_debug_error("Only SOCK_DRAM is supported\n"); 394 maxio = NFS_MAXDATA; 395 } 396 397 /* Get the maximum amount of data that can be transferred in one write transfer */ 398 399 if ((argp->flags & NFSMNT_WSIZE) != 0 && argp->wsize > 0) 400 { 401 nprmt->wsize = argp->wsize; 402 403 /* Round down to multiple of blocksize */ 404 405 nprmt->wsize &= ~(NFS_FABLKSIZE - 1); 406 if (nprmt->wsize <= 0) 407 { 408 nprmt->wsize = NFS_FABLKSIZE; 409 } 410 } 411 412 if (nprmt->wsize > maxio) 413 { 414 nprmt->wsize = maxio; 415 } 416 417 if (nprmt->wsize > MAXBSIZE) 418 { 419 nprmt->wsize = MAXBSIZE; 420 } 421 422 /* Get the maximum amount of data that can be transferred in one read transfer */ 423 424 if ((argp->flags & NFSMNT_RSIZE) != 0 && argp->rsize > 0) 425 { 426 nprmt->rsize = argp->rsize; 427 428 /* Round down to multiple of blocksize */ 429 430 nprmt->rsize &= ~(NFS_FABLKSIZE - 1); 431 if (nprmt->rsize <= 0) 432 { 433 nprmt->rsize = NFS_FABLKSIZE; 434 } 435 } 436 437 if (nprmt->rsize > maxio) 438 { 439 nprmt->rsize = maxio; 440 } 441 442 if (nprmt->rsize > MAXBSIZE) 443 { 444 nprmt->rsize = MAXBSIZE; 445 } 446 447 /* Get the maximum amount of data that can be transferred in directory transfer */ 448 449 if ((argp->flags & NFSMNT_READDIRSIZE) != 0 && argp->readdirsize > 0) 450 { 451 nprmt->readdirsize = argp->readdirsize; 452 453 /* Round down to multiple of blocksize */ 454 455 nprmt->readdirsize &= ~(NFS_DIRBLKSIZ - 1); 456 if (nprmt->readdirsize < NFS_DIRBLKSIZ) 457 { 458 nprmt->readdirsize = NFS_DIRBLKSIZ; 459 } 460 } 461 else if (argp->flags & NFSMNT_RSIZE) 462 { 463 nprmt->readdirsize = nprmt->rsize; 464 } 465 466 if (nprmt->readdirsize > maxio) 467 { 468 nprmt->readdirsize = maxio; 469 } 470} 471 472/**************************************************************************** 473 * Name: nfs_bind 474 * 475 * Description: 476 * This implements a portion of the mount operation. This function allocates 477 * and initializes the mountpoint private data and gets mount information 478 * from the NFS server. The final binding of the private data (containing 479 * NFS server mount information) to the mountpoint is performed by mount(). 480 * 481 * Returned Value: 482 * 0 on success; a negated errno value on failure. 483 * 484 ****************************************************************************/ 485 486int nfs_bind(struct Vnode *blkdriver, const void *data, 487 void **handle, const char *relpath) 488{ 489 struct nfs_args *argp = (struct nfs_args *)data; 490 struct nfsmount *nmp = NULL; 491 struct rpcclnt *rpc = NULL; 492 struct rpc_call_fs getattr; 493 struct rpc_reply_getattr resok; 494 struct nfs_mount_parameters nprmt; 495 uint32_t buflen; 496 uint32_t pathlen; 497 uint32_t tmp; 498 int error = 0; 499 pthread_mutexattr_t attr; 500 501 DEBUGASSERT(data && handle); 502 503 /* Set default values of the parameters. These may be overridden by 504 * settings in the argp->flags. 505 */ 506 507 nprmt.timeo = NFS_TIMEO; 508 nprmt.retry = NFS_RETRANS; 509 nprmt.wsize = NFS_WSIZE; 510 nprmt.rsize = NFS_RSIZE; 511 nprmt.readdirsize = NFS_READDIRSIZE; 512 513 nfs_decode_args(&nprmt, argp); 514 515 /* Determine the size of a buffer that will hold one RPC data transfer. 516 * First, get the maximum size of a read and a write transfer. 517 */ 518 519 pathlen = strlen(argp->path); 520 if (pathlen >= NFS_MOUNT_PATH_MAX_SIZE) { 521 return -ENAMETOOLONG; 522 } 523 524 buflen = SIZEOF_rpc_call_write(nprmt.wsize); 525 tmp = SIZEOF_rpc_reply_read(nprmt.rsize); 526 527 /* The buffer size will be the maximum of those two sizes */ 528 529 if (tmp > buflen) 530 { 531 buflen = tmp; 532 } 533 534 /* But don't let the buffer size exceed the MSS of the socket type. 535 * 536 * In the case where there are multiple network devices with different 537 * link layer protocols, each network device may support a different 538 * UDP MSS value. Here we arbitrarily select the minimum MSS for 539 * that case. 540 */ 541 542 /* Create an instance of the mountpt state structure */ 543 544 nmp = (struct nfsmount *)malloc(SIZEOF_nfsmount(buflen)); 545 if (!nmp) 546 { 547 nfs_debug_error("Failed to allocate mountpoint structure\n"); 548 return -ENOMEM; 549 } 550 551 (void)memset_s(nmp, SIZEOF_nfsmount(buflen), 0, SIZEOF_nfsmount(buflen)); 552 553 /* Save the allocated I/O buffer size */ 554 555 nmp->nm_buflen = (uint16_t)buflen; 556 557 nmp->nm_so = -1; 558 559 /* Initialize the allocated mountpt state structure. */ 560 561 (void)pthread_mutexattr_init(&attr); 562 (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 563 error = pthread_mutex_init(&nmp->nm_mux, &attr); 564 if (error) 565 { 566 return -error; 567 } 568 569 /* Initialize NFS */ 570 571 nfs_true = txdr_unsigned(TRUE); 572 nfs_false = txdr_unsigned(FALSE); 573 nfs_xdrneg1 = txdr_unsigned(-1); 574 575 rpcclnt_init(); 576 577 /* Set initial values of other fields */ 578 579 nmp->nm_timeo = nprmt.timeo; 580 nmp->nm_retry = nprmt.retry; 581 nmp->nm_wsize = nprmt.wsize; 582 nmp->nm_rsize = nprmt.rsize; 583 nmp->nm_readdirsize = nprmt.readdirsize; 584 nmp->nm_fhsize = NFSX_V3FHMAX; 585 586 (void)strncpy_s(nmp->nm_path, sizeof(nmp->nm_path), argp->path, pathlen); 587 (void)memcpy_s(&nmp->nm_nam, sizeof(struct sockaddr), &argp->addr, argp->addrlen); 588 589 /* Set up the sockets and per-host congestion */ 590 591 nmp->nm_sotype = argp->sotype; 592 593 if (nmp->nm_sotype == SOCK_DGRAM || nmp->nm_sotype == SOCK_STREAM) 594 { 595 /* Connection-less... connect now */ 596 597 /* Create an instance of the rpc state structure */ 598 599 rpc = (struct rpcclnt *)malloc(sizeof(struct rpcclnt)); 600 if (!rpc) 601 { 602 nfs_debug_error("Failed to allocate rpc structure\n"); 603 error = ENOMEM; 604 goto bad; 605 } 606 607 (void)memset_s(rpc, sizeof(struct rpcclnt), 0, sizeof(struct rpcclnt)); 608 609 nfs_debug_info("Connecting\n"); 610 611 /* Translate nfsmnt flags -> rpcclnt flags */ 612 613 rpc->rc_path = nmp->nm_path; 614 rpc->rc_name = &nmp->nm_nam; 615 rpc->rc_sotype = nmp->nm_sotype; 616 rpc->rc_retry = nmp->nm_retry; 617 rpc->rc_so = -1; 618 619 nmp->nm_rpcclnt = rpc; 620 621 error = rpcclnt_connect(nmp->nm_rpcclnt); 622 if (error != OK) 623 { 624 nfs_debug_error("nfs_connect failed: %d\n", error); 625 goto bad; 626 } 627 } 628 629 nmp->nm_mounted = true; 630 nmp->nm_so = nmp->nm_rpcclnt->rc_so; 631 nmp->nm_head = NULL; 632 nmp->nm_dir = NULL; 633 nmp->nm_fhsize = nmp->nm_rpcclnt->rc_fhsize; 634 (void)memcpy_s(&nmp->nm_fh, sizeof(nfsfh_t), &nmp->nm_rpcclnt->rc_fh, sizeof(nfsfh_t)); 635 636 /* Get the file attributes */ 637 638 getattr.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize); 639 (void)memcpy_s(&getattr.fs.fsroot.handle, sizeof(nfsfh_t), &nmp->nm_fh, sizeof(nfsfh_t)); 640 641 error = nfs_request(nmp, NFSPROC_GETATTR, 642 (void *)&getattr, /* sizeof(struct FS3args) */ 643 (sizeof(getattr.fs.fsroot.length) + nmp->nm_fhsize), 644 (void *)&resok, sizeof(struct rpc_reply_getattr)); 645 if (error) 646 { 647 nfs_debug_error("nfs_request failed: %d\n", error); 648 goto bad; 649 } 650 651 /* Save the file attributes */ 652 653 (void)memcpy_s(&nmp->nm_fattr, sizeof(struct nfs_fattr), &resok.attr, sizeof(struct nfs_fattr)); 654 655 /* Mounted! */ 656 657 *handle = (void *)nmp; 658 659 nfs_debug_info("Successfully mounted\n"); 660 return OK; 661 662bad: 663 if (nmp) 664 { 665 /* Disconnect from the server */ 666 667 if (nmp->nm_rpcclnt) 668 { 669 rpcclnt_disconnect(nmp->nm_rpcclnt); 670 free(nmp->nm_rpcclnt); 671 nmp->nm_rpcclnt = NULL; 672 } 673 674 /* Free connection-related resources */ 675 676 (void)pthread_mutex_destroy(&nmp->nm_mux); 677 678 free(nmp); 679 nmp = NULL; 680 } 681 682 return -error; /*lint !e438*/ 683} 684 685 686static enum VnodeType filetype_to_vnodetype(uint32_t filetype) 687{ 688 if (filetype < 0 || filetype > 7) 689 { 690 return VNODE_TYPE_UNKNOWN; 691 } 692 693 enum VnodeType transfer_table[8] = 694 { 695 VNODE_TYPE_UNKNOWN, 696 VNODE_TYPE_REG, 697 VNODE_TYPE_DIR, 698 VNODE_TYPE_BLK, 699 VNODE_TYPE_CHR, 700 VNODE_TYPE_LNK, 701 VNODE_TYPE_UNKNOWN, 702 VNODE_TYPE_FIFO 703 }; 704 705 return transfer_table[filetype]; 706} 707 708int nfs_mount(const char *server_ip_and_path, const char *mount_path, 709 unsigned int uid, unsigned int gid) 710{ 711 struct nfs_args nfs_args = {0}; 712 char *server_ip_addr = NULL; 713 char *server_nfs_path = NULL; 714 int found_colon = 0; 715 unsigned int pos; 716 int ret = -1; 717 struct sockaddr_in *nfs_srv_addr = NULL; 718 size_t len; 719 720 rpcclnt_setuidgid(uid, gid); 721 722 len = strlen(server_ip_and_path); 723 for (pos = 0; pos < len; pos++) 724 { 725 if (*(server_ip_and_path + pos) == ':') 726 { 727 found_colon = 1; 728 break; 729 } 730 } 731 732 if (!found_colon) 733 { 734 set_errno(ENOENT); 735 goto nfs_mount_out; 736 } 737 738 server_ip_addr = (char *)malloc(pos + 1); 739 if (server_ip_addr == NULL) 740 { 741 nfs_debug_info("malloc failure\n"); 742 set_errno(ENOMEM); 743 goto nfs_mount_out; 744 } 745 746 ret = strncpy_s(server_ip_addr, pos + 1, server_ip_and_path, pos); 747 if (ret != EOK) 748 { 749 set_errno(ENOBUFS); 750 goto nfs_free_node_out; 751 } 752 *(server_ip_addr + pos) = '\0'; 753 server_nfs_path = (char *)(server_ip_and_path + pos + 1); 754 755 (void)memset_s(&nfs_args, sizeof(nfs_args), 0, sizeof(nfs_args)); 756 757 if (g_NFSMOUNT_HOOK != NULL) 758 { 759 g_NFSMOUNT_HOOK(&nfs_args); 760 } 761 762 nfs_args.path = server_nfs_path; /* server nfs dir */ 763 764 nfs_srv_addr = (struct sockaddr_in *)&nfs_args.addr; 765 nfs_srv_addr->sin_family = AF_INET; 766 ret = inet_pton(AF_INET, server_ip_addr, &nfs_srv_addr->sin_addr.s_addr); 767 if (ret != 1) 768 { 769 ret = -1; 770 set_errno(ECONNREFUSED); 771 goto nfs_free_node_out; 772 } 773 nfs_srv_addr->sin_port = htons(PMAPPORT); 774 775 nfs_args.addrlen = sizeof(nfs_args.addr); 776#if (NFS_PROTO_TYPE == NFS_IPPROTO_TCP) 777 nfs_args.sotype = SOCK_STREAM; 778#elif (NFS_PROTO_TYPE == NFS_IPPROTO_UDP) 779 nfs_args.sotype = SOCK_DGRAM; 780#endif 781 782 PRINTK("Mount nfs on %s:%s, uid:%d, gid:%d\n", server_ip_addr, server_nfs_path, uid, gid); 783 ret = mount((const char *)NULL, mount_path, "nfs", 0, &nfs_args); 784 785nfs_free_node_out: 786 free(server_ip_addr); 787 788nfs_mount_out: 789 if (ret) 790 { 791 perror("mount nfs error"); 792 return -1; 793 } 794 PRINTK("Mount nfs finished.\n"); 795 return 0; 796} 797 798int vfs_nfs_mount(struct Mount *mnt, struct Vnode *device, const void *data) 799{ 800 struct nfsmount *nmp = NULL; 801 struct Vnode *vp = NULL; 802 803 int ret = VnodeAlloc(&nfs_vops, &vp); 804 if (ret != OK) 805 { 806 return -EADDRNOTAVAIL; 807 } 808 809 struct nfsnode *root = zalloc(sizeof(struct nfsnode)); 810 if (root == NULL) 811 { 812 (void)VnodeFree(vp); 813 return -EADDRNOTAVAIL; 814 } 815 816 ret = nfs_bind(NULL, data, (void **)(&nmp), NULL); 817 if (ret != OK || nmp == NULL) 818 { 819 (void)VnodeFree(vp); 820 free(root); 821 return -EAGAIN; 822 } 823 vp->originMount = mnt; 824 vp->fop = &nfs_fops; 825 vp->data = root; 826 root->n_fhsize = nmp->nm_fhsize; 827 (void)memcpy_s(&(root->n_fhandle), root->n_fhsize, &(nmp->nm_fh), nmp->nm_fhsize); 828 root->n_pfhsize = 0; 829 mnt->vnodeCovered = vp; 830 mnt->data = nmp; 831 root->n_next = nmp->nm_head; 832 nmp->nm_head = root; 833 834 ret = vfs_nfs_stat_internal(nmp, root); 835 if (ret == OK) 836 { 837 vp->type = root->n_type; 838 } 839 nmp->nm_permission = mnt->vnodeBeCovered->mode & 0777; 840 nmp->nm_gid = mnt->vnodeBeCovered->gid; 841 nmp->nm_uid = mnt->vnodeBeCovered->uid; 842 vp->mode = type_to_mode(vp->type, nmp->nm_permission); 843 vp->gid = nmp->nm_gid; 844 vp->uid = nmp->nm_uid; 845 return OK; 846} 847 848int vfs_nfs_lookup(struct Vnode *parent, const char *path, int len, struct Vnode **vpp) 849{ 850 int ret; 851 struct nfs_fattr obj_attributes; 852 struct nfsmount *nmp; 853 char filename[len + 1]; 854 struct file_handle fhandle; 855 struct nfsnode *parent_nfs_node = NULL; 856 struct nfsnode *nfs_node = NULL; 857 nmp = (struct nfsmount *)(parent->originMount->data); 858 nfs_mux_take(nmp); 859 parent_nfs_node = (struct nfsnode *)parent->data; 860 fhandle.length = parent_nfs_node->n_fhsize; 861 (void)memcpy_s(&(fhandle.handle), fhandle.length, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize); 862 filename[len] = '\0'; 863 (void)memcpy_s(filename, (len + 1), path, len); 864 865 ret = nfs_lookup(nmp, filename, &fhandle, &obj_attributes, NULL); 866 if (ret != OK) 867 { 868 nfs_mux_release(nmp); 869 return -ENOENT; 870 } 871 872 /* Initialize the file private data. 873 * 874 * Copy the file handle. 875 */ 876 nfs_node = zalloc(sizeof(struct nfsnode)); 877 nfs_node->n_fhsize = (uint8_t)fhandle.length; 878 memcpy_s(&(nfs_node->n_fhandle), nfs_node->n_fhsize, &(fhandle.handle), fhandle.length); 879 nfs_node->n_pfhsize = parent_nfs_node->n_fhsize; 880 (void)memcpy_s(&(nfs_node->n_pfhandle), NFSX_V3FHMAX, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize); 881 nfs_node->n_name = zalloc(sizeof(filename)); 882 memcpy_s(nfs_node->n_name, (len + 1), filename, sizeof(filename)); 883 nfs_node->n_next = nmp->nm_head; 884 nmp->nm_head = nfs_node; 885 886 /* Save the file attributes */ 887 nfs_attrupdate(nfs_node, &obj_attributes); 888 889 (void)VnodeAlloc(&nfs_vops, vpp); 890 (*vpp)->parent = parent; 891 (*vpp)->fop = &nfs_fops; 892 (*vpp)->originMount = parent->originMount; 893 (*vpp)->data = nfs_node; 894 (*vpp)->type = filetype_to_vnodetype(nfs_node->n_type); 895 (*vpp)->mode = type_to_mode((*vpp)->type, nmp->nm_permission); 896 (*vpp)->gid = nmp->nm_gid; 897 (*vpp)->uid = nmp->nm_uid; 898 nfs_mux_release(nmp); 899 return OK; 900} 901 902int vfs_nfs_stat(struct Vnode *node, struct stat *buf) 903{ 904 struct nfsnode *nfs_node = NULL; 905 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 906 nfs_mux_take(nmp); 907 nfs_node = (struct nfsnode *)node->data; 908 buf->st_mode = node->mode; 909 buf->st_gid = node->gid; 910 buf->st_uid = node->uid; 911 buf->st_size = (off_t)nfs_node->n_size; 912 buf->st_blksize = 0; 913 buf->st_blocks = 0; 914 buf->st_mtime = nfs_node->n_timestamp.tv_sec; 915 buf->st_atime = nfs_node->n_atime; 916 buf->st_ctime = nfs_node->n_ctime; 917 918 /* Adapt to kstat member "long tv_sec" */ 919 buf->__st_mtim32.tv_sec = (long)nfs_node->n_timestamp.tv_sec; 920 buf->__st_atim32.tv_sec = (long)nfs_node->n_atime; 921 buf->__st_ctim32.tv_sec = (long)nfs_node->n_ctime; 922 923 nfs_mux_release(nmp); 924 return OK; 925} 926 927int vfs_nfs_opendir(struct Vnode *node, struct fs_dirent_s *dir) 928{ 929 int ret; 930 struct nfsdir_s *nfs_dir = NULL; 931 struct nfsnode *nfs_node = NULL; 932 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 933 if (node->type != VNODE_TYPE_DIR) { 934 return -ENOTDIR; 935 } 936 nfs_mux_take(nmp); 937 nfs_node = (struct nfsnode *)node->data; 938 ret = nfs_checkmount(nmp); 939 if (ret != OK) { 940 ret = -ret; 941 nfs_debug_error("nfs_checkmount failed: %d\n", ret); 942 goto errout_with_mutex; 943 } 944 nfs_dir = (struct nfsdir_s *)malloc(sizeof(struct nfsdir_s)); 945 if (!nfs_dir) { 946 ret = -ENOMEM; 947 goto errout_with_mutex; 948 } 949 nfs_dir->nfs_fhsize = nfs_node->n_fhsize; 950 nfs_dir->nfs_cookie[0] = 0; 951 nfs_dir->nfs_cookie[1] = 0; 952 (void)memcpy_s(nfs_dir->nfs_fhandle, DIRENT_NFS_MAXHANDLE, &(nfs_node->n_fhandle), DIRENT_NFS_MAXHANDLE); 953 dir->u.fs_dir = (fs_dir_s)nfs_dir; 954 ret = OK; 955 956 nfs_dir->nfs_next = nmp->nm_dir; 957 nmp->nm_dir = nfs_dir; 958 nfs_dir->nfs_dir = dir; 959 nfs_dir->nfs_entries = NULL; 960 961errout_with_mutex: 962 nfs_mux_release(nmp); 963 return ret; 964} 965 966int vfs_nfs_readdir(struct Vnode *node, struct fs_dirent_s *dir) 967{ 968 struct nfsmount *nmp; 969 struct file_handle fhandle; 970 struct nfs_fattr obj_attributes; 971 struct nfsdir_s *nfs_dir = NULL; 972 struct entry3 *entry = NULL; 973 struct entry3 *entry_pos = NULL; 974 975 /* Use 2 cookies */ 976 977 uint32_t cookies[2]; 978 uint32_t tmp; 979 uint32_t *ptr = NULL; 980 size_t d_name_size; 981 int reqlen; 982 int error = 0; 983 int i = 0; 984 985 /* Sanity checks */ 986 987 /* Recover our private data from the vnode instance */ 988 989 nmp = (struct nfsmount *)(node->originMount->data); 990 991 /* Make sure that the mount is still healthy */ 992 993 nfs_mux_take(nmp); 994 error = nfs_checkmount(nmp); 995 if (error != OK) 996 { 997 nfs_debug_error("nfs_checkmount failed: %d\n", error); 998 goto errout_with_mutex; 999 } 1000 1001 /* Request a block directory entries, copying directory information from 1002 * the dirent structure. 1003 */ 1004 nfs_dir = (struct nfsdir_s *)dir->u.fs_dir; 1005 cookies[0] = 0; 1006 cookies[1] = 0; 1007 1008 if (nfs_dir && nfs_dir->nfs_entries && (nfs_dir->nfs_entries->file_id[0] == (uint32_t)EOF)) 1009 { 1010 error = ENOENT; 1011 free(nfs_dir->nfs_entries); 1012 nfs_dir->nfs_entries = NULL; 1013 goto errout_with_mutex; 1014 } 1015 while (i < dir->read_cnt) 1016 { 1017 if (!nfs_dir->nfs_entries) 1018 { 1019 entry_pos = nfs_dir->nfs_entries; 1020 do 1021 { 1022 ptr = (uint32_t *)&nmp->nm_msgbuffer.readdir.readdir; 1023 reqlen = 0; 1024 1025 /* Copy the variable length, directory file handle */ 1026 1027 *ptr++ = txdr_unsigned((uint32_t)nfs_dir->nfs_fhsize); 1028 reqlen += sizeof(uint32_t); 1029 1030 (void)memcpy_s(ptr, nfs_dir->nfs_fhsize, nfs_dir->nfs_fhandle, nfs_dir->nfs_fhsize); 1031 reqlen += (int)nfs_dir->nfs_fhsize; 1032 ptr += uint32_increment((int)nfs_dir->nfs_fhsize); 1033 1034 /* Cookie and cookie verifier */ 1035 1036 ptr[0] = cookies[0]; 1037 ptr[1] = cookies[1]; 1038 ptr += 2; 1039 reqlen += 2 * sizeof(uint32_t); 1040 1041 (void)memcpy_s(ptr, DIRENT_NFS_VERFLEN, nfs_dir->nfs_verifier, DIRENT_NFS_VERFLEN); 1042 ptr += uint32_increment(DIRENT_NFS_VERFLEN); 1043 reqlen += DIRENT_NFS_VERFLEN; 1044 1045 /* Number of directory entries (We currently only process one entry at a time) */ 1046 1047 *ptr = txdr_unsigned((uint32_t)nmp->nm_readdirsize); 1048 reqlen += sizeof(uint32_t); 1049 1050 /* And read the directory */ 1051 1052 nfs_statistics(NFSPROC_READDIR); 1053 error = nfs_request(nmp, NFSPROC_READDIR, 1054 (void *)&nmp->nm_msgbuffer.readdir, reqlen, 1055 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 1056 1057 if (error != OK) 1058 { 1059 nfs_debug_error("nfs_request failed: %d\n", error); 1060 goto errout_with_mutex; 1061 } 1062 1063 /* A new group of entries was successfully read. Process the 1064 * information contained in the response header. This information 1065 * includes: 1066 * 1067 * 1) Attributes follow indication - 4 bytes 1068 * 2) Directory attributes - sizeof(struct nfs_fattr) 1069 * 3) Cookie verifier - NFSX_V3COOKIEVERF bytes 1070 * 4) Values follows indication - 4 bytes 1071 */ 1072 1073 ptr = (uint32_t *)&((struct rpc_reply_readdir *)nmp->nm_iobuffer)->readdir; 1074 1075 /* Check if attributes follow, if 0 so Skip over the attributes */ 1076 1077 tmp = *ptr++; 1078 if (tmp != 0) 1079 { 1080 /* Attributes are not currently used */ 1081 1082 ptr += uint32_increment(sizeof(struct nfs_fattr)); 1083 } 1084 1085 /* Save the verification cookie */ 1086 1087 (void)memcpy_s(nfs_dir->nfs_verifier, DIRENT_NFS_VERFLEN, ptr, DIRENT_NFS_VERFLEN); 1088 ptr += uint32_increment(DIRENT_NFS_VERFLEN); 1089 1090 /* Check if values follow. If no values follow, then the EOF indication 1091 * will appear next. 1092 */ 1093 1094 tmp = *ptr++; 1095 if (tmp == 0) 1096 { 1097 /* No values follow, then the reply should consist only of a 4-byte 1098 * end-of-directory indication. 1099 */ 1100 1101 tmp = *ptr++; 1102 if (tmp != 0) 1103 { 1104 error = ENOENT; 1105 } 1106 1107 /* What would it mean if there were not data and we not at the end of 1108 * file? 1109 */ 1110 1111 else 1112 { 1113 error = EAGAIN; 1114 } 1115 goto errout_with_mutex; 1116 } 1117 1118 /* If we are not at the end of the directory listing, then a set of entries 1119 * will follow the header. Each entry is of the form: 1120 * 1121 * File ID (8 bytes) 1122 * Name length (4 bytes) 1123 * Name string (varaiable size but in multiples of 4 bytes) 1124 * Cookie (8 bytes) 1125 * next entry (4 bytes) 1126 */ 1127 1128 do 1129 { 1130 NFS_DIR_ENTRY_MALLOC(entry); 1131 1132 /* There is an entry. Skip over the file ID and point to the length */ 1133 1134 entry->file_id[0] = *ptr++; 1135 entry->file_id[1] = *ptr++; /*lint !e662 !e661*/ 1136 1137 /* Get the length and point to the name */ 1138 1139 tmp = *ptr++; /*lint !e662 !e661*/ 1140 entry->name_len = fxdr_unsigned(uint32_t, tmp); 1141 entry->contents = (uint8_t *)malloc(entry->name_len + 1); 1142 if (!entry->contents) 1143 { 1144 free(entry); 1145 entry = NULL; 1146 goto errout_with_memory; 1147 } 1148 (void)memset_s(entry->contents, entry->name_len + 1, 0, entry->name_len + 1); 1149 1150 error = strncpy_s((char *)entry->contents, entry->name_len + 1, (const char *)ptr, entry->name_len); 1151 if (error != EOK) 1152 { 1153 free(entry->contents); 1154 entry->contents = NULL; 1155 free(entry); 1156 entry = NULL; 1157 error = ENOBUFS; 1158 goto errout_with_memory; 1159 } 1160 /* Increment the pointer past the name (allowing for padding). ptr 1161 * now points to the cookie. 1162 */ 1163 1164 ptr += uint32_increment(entry->name_len); 1165 1166 /* Save the cookie and increment the pointer to the next entry */ 1167 1168 entry->cookie[0] = *ptr++; 1169 entry->cookie[1] = *ptr++; 1170 1171 /* Get the file attributes associated with this name and return 1172 * the file type. 1173 */ 1174 1175 if (strcmp((char *)entry->contents, ".") == 0 || strcmp((char *)entry->contents, "..") == 0) 1176 { 1177 NFS_DIR_ENTRY_FREE(entry); 1178 continue; 1179 } 1180 1181 if (!nfs_dir->nfs_entries) 1182 { 1183 entry_pos = entry; 1184 nfs_dir->nfs_entries = entry; 1185 } 1186 else 1187 { 1188 entry_pos->next = entry; 1189 entry_pos = entry; 1190 } 1191 } 1192 while (*ptr++); 1193 if (entry_pos) 1194 { 1195 cookies[0] = entry_pos->cookie[0]; 1196 cookies[1] = entry_pos->cookie[1]; 1197 } 1198 } 1199 while (!(*ptr)); 1200 1201 if (!nfs_dir->nfs_entries) 1202 { 1203 error = ENOENT; 1204 goto errout_with_mutex; 1205 } 1206 1207 NFS_DIR_ENTRY_MALLOC(entry); 1208 1209 /* There is an entry. Skip over the file ID and point to the length */ 1210 1211 entry->file_id[0] = (uint32_t)EOF; 1212 if (!entry_pos) 1213 { 1214 error = ENOENT; 1215 NFS_DIR_ENTRY_FREE(entry); 1216 goto errout_with_mutex; 1217 } 1218 entry_pos->next = entry; 1219 entry_pos = entry; 1220 } 1221 1222 entry_pos = nfs_dir->nfs_entries; 1223 if (nfs_dir->nfs_entries->file_id[0] == (uint32_t)EOF) 1224 { 1225 error = ENOENT; 1226 goto errout_with_mutex; 1227 } 1228 1229 d_name_size = sizeof(dir->fd_dir[i].d_name); 1230 error = memcpy_s(dir->fd_dir[i].d_name, d_name_size, (const char *)entry_pos->contents, (size_t)entry_pos->name_len); 1231 if (error != EOK) 1232 { 1233 error = ENOBUFS; 1234 goto errout_with_memory; 1235 } 1236 if (entry_pos->name_len >= d_name_size) 1237 { 1238 dir->fd_dir[i].d_name[d_name_size - 1] = '\0'; 1239 } 1240 else 1241 { 1242 dir->fd_dir[i].d_name[entry_pos->name_len] = '\0'; 1243 } 1244 1245 nfs_dir->nfs_entries = entry_pos->next; 1246 NFS_DIR_ENTRY_FREE(entry_pos); 1247 1248 fhandle.length = (uint32_t)nfs_dir->nfs_fhsize; 1249 (void)memcpy_s(&fhandle.handle, DIRENT_NFS_MAXHANDLE, nfs_dir->nfs_fhandle, DIRENT_NFS_MAXHANDLE); 1250 1251 error = nfs_lookup(nmp, dir->fd_dir[i].d_name, &fhandle, &obj_attributes, NULL); 1252 if (error != OK) 1253 { 1254 nfs_debug_error("nfs_lookup failed: %d\n", error); 1255 goto errout_with_memory; 1256 } 1257 1258 /* Set the dirent file type */ 1259 1260 tmp = fxdr_unsigned(uint32_t, obj_attributes.fa_type); 1261 switch (tmp) 1262 { 1263 default: 1264 case NFNON: /* Unknown type */ 1265 case NFSOCK: /* Socket */ 1266 case NFLNK: /* Symbolic link */ 1267 break; 1268 1269 case NFREG: /* Regular file */ 1270 dir->fd_dir[i].d_type = DT_REG; 1271 break; 1272 1273 case NFDIR: /* Directory */ 1274 dir->fd_dir[i].d_type = DT_DIR; 1275 break; 1276 1277 case NFBLK: /* Block special device file */ 1278 dir->fd_dir[i].d_type = DT_BLK; 1279 break; 1280 1281 case NFFIFO: /* Named FIFO */ 1282 case NFCHR: /* Character special device file */ 1283 dir->fd_dir[i].d_type = DT_CHR; 1284 break; 1285 } 1286 dir->fd_position++; 1287 dir->fd_dir[i].d_off = dir->fd_position; 1288 dir->fd_dir[i].d_reclen = (uint16_t)sizeof(struct dirent); 1289 i++; 1290 } 1291 nfs_mux_release(nmp); 1292 return i; 1293 1294errout_with_memory: 1295 for (entry_pos = nfs_dir->nfs_entries; entry_pos != NULL; entry_pos = nfs_dir->nfs_entries) 1296 { 1297 nfs_dir->nfs_entries = entry_pos->next; 1298 NFS_DIR_ENTRY_FREE(entry_pos); 1299 } 1300errout_with_mutex: 1301 nfs_mux_release(nmp); 1302 if (error == ENOENT && i > 0) 1303 { 1304 return i; 1305 } 1306 return -error; 1307} 1308extern int nfs_getfilename(char *dstpath, unsigned int dstpathLen, const char *srcpath, unsigned int maxlen); 1309extern int nfs_rename(struct Vnode *mountpt, const char *oldrelpath, const char *newrelpath); 1310int vfs_nfs_rename(struct Vnode *from_vnode, struct Vnode *to_parent, 1311 const char *from_name, const char *to_name) 1312{ 1313 int error; 1314 int reqlen; 1315 int namelen; 1316 uint32_t *ptr = NULL; 1317 struct Vnode *to_vnode = NULL; 1318 struct Vnode *from_parent = from_vnode->parent; 1319 struct nfsnode *from_node = NULL; 1320 struct nfsnode *to_node = NULL; 1321 struct nfsmount *nmp = (struct nfsmount *)(to_parent->originMount->data); 1322 1323 nfs_mux_take(nmp); 1324 error = nfs_checkmount(nmp); 1325 if (error != OK) 1326 { 1327 nfs_debug_error("nfs_checkmount failed: %d\n", error); 1328 goto errout_with_mutex; 1329 } 1330 1331 from_node = (struct nfsnode *)from_parent->data; 1332 to_node = (struct nfsnode *)to_parent->data; 1333 1334 ptr = (uint32_t *)&nmp->nm_msgbuffer.renamef.rename; 1335 reqlen = 0; 1336 1337 /* Copy the variable length, 'from' directory file handle */ 1338 1339 *ptr++ = txdr_unsigned(from_node->n_fhsize); 1340 reqlen += sizeof(uint32_t); 1341 1342 (void)memcpy_s(ptr, from_node->n_fhsize, &from_node->n_fhandle, from_node->n_fhsize); 1343 reqlen += (int)from_node->n_fhsize; 1344 ptr += uint32_increment(from_node->n_fhsize); 1345 1346 /* Copy the variable-length 'from' object name */ 1347 1348 namelen = strlen(from_name); 1349 1350 *ptr++ = txdr_unsigned(namelen); 1351 reqlen += sizeof(uint32_t); 1352 1353 (void)memcpy_s(ptr, namelen, from_name, namelen); 1354 reqlen += uint32_alignup(namelen); 1355 ptr += uint32_increment(namelen); 1356 1357 /* Copy the variable length, 'to' directory file handle */ 1358 1359 *ptr++ = txdr_unsigned(to_node->n_fhsize); 1360 reqlen += sizeof(uint32_t); 1361 1362 (void)memcpy_s(ptr, to_node->n_fhsize, &to_node->n_fhandle, to_node->n_fhsize); 1363 ptr += uint32_increment(to_node->n_fhsize); 1364 reqlen += (int)to_node->n_fhsize; 1365 1366 /* Copy the variable-length 'to' object name */ 1367 1368 namelen = strlen(to_name); 1369 1370 *ptr++ = txdr_unsigned(namelen); 1371 reqlen += sizeof(uint32_t); 1372 1373 (void)memcpy_s(ptr, namelen, to_name, namelen); 1374 reqlen += uint32_alignup(namelen); 1375 1376 /* Perform the RENAME RPC */ 1377 1378 nfs_statistics(NFSPROC_RENAME); 1379 error = nfs_request(nmp, NFSPROC_RENAME, 1380 (void *)&nmp->nm_msgbuffer.renamef, reqlen, 1381 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 1382 if (error != OK) 1383 { 1384 nfs_debug_error("nfs_request returned: %d\n", error); 1385 goto errout_with_mutex; 1386 } 1387 1388 error = vfs_nfs_lookup(to_parent, to_name, strlen(to_name), &to_vnode); 1389 if (error != OK) 1390 { 1391 error = -error; 1392 nfs_debug_error("nfs_rename not finish\n"); 1393 goto errout_with_mutex; 1394 } 1395 vfs_nfs_reclaim(from_vnode); 1396 from_vnode->data = to_vnode->data; 1397 from_vnode->parent = to_parent; 1398 to_vnode->data = NULL; 1399 VnodeFree(to_vnode); 1400 1401errout_with_mutex: 1402 nfs_mux_release(nmp); 1403 return -error; 1404} 1405 1406int vfs_nfs_mkdir(struct Vnode *parent, const char *dirname, mode_t mode, struct Vnode **vpp) 1407{ 1408 struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data); 1409 struct nfsnode *parent_nfs_node = NULL; 1410 struct nfs_fattr obj_attributes; 1411 struct nfsnode *target_node = NULL; 1412 struct file_handle fhandle; 1413 uint32_t *ptr = NULL; 1414 uint32_t tmp; 1415 int namelen; 1416 int reqlen; 1417 int error; 1418 1419 /* Sanity checks */ 1420 1421 DEBUGASSERT(parent && parent->data); 1422 1423 /* Check if the mount is still healthy */ 1424 1425 nfs_mux_take(nmp); 1426 error = nfs_checkmount(nmp); 1427 if (error != OK) 1428 { 1429 nfs_debug_error("nfs_checkmount: %d\n", error); 1430 goto errout_with_mutex; 1431 } 1432 1433 parent_nfs_node = (struct nfsnode *)parent->data; 1434 1435 /* Format the MKDIR call message arguments */ 1436 1437 ptr = (uint32_t *)&nmp->nm_msgbuffer.mkdir.mkdir; 1438 reqlen = 0; 1439 1440 /* Copy the variable length, directory file handle */ 1441 1442 *ptr++ = txdr_unsigned(parent_nfs_node->n_fhsize); 1443 reqlen += sizeof(uint32_t); 1444 1445 memcpy_s(ptr, parent_nfs_node->n_fhsize, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize); 1446 ptr += uint32_increment(parent_nfs_node->n_fhsize); 1447 reqlen += (int)parent_nfs_node->n_fhsize; 1448 1449 /* Copy the variable-length directory name */ 1450 1451 namelen = strlen(dirname); 1452 1453 *ptr++ = txdr_unsigned(namelen); 1454 reqlen += sizeof(uint32_t); 1455 1456 (void)memcpy_s(ptr, namelen, dirname, namelen); 1457 ptr += uint32_increment(namelen); 1458 reqlen += uint32_alignup(namelen); 1459 1460 /* Set the mode. NOTE: Here we depend on the fact that the NuttX and NFS 1461 * bit settings are the same (at least for the bits of interest). 1462 */ 1463 1464 *ptr++ = nfs_true; /* True: mode value follows */ 1465 reqlen += sizeof(uint32_t); 1466 1467 if (!mode) 1468 { 1469 mode = (NFSMODE_IXOTH | NFSMODE_IROTH | 1470 NFSMODE_IXGRP | NFSMODE_IRGRP | 1471 NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR); 1472 } 1473 tmp = mode & (NFSMODE_IXOTH | NFSMODE_IWOTH | NFSMODE_IROTH | 1474 NFSMODE_IXGRP | NFSMODE_IWGRP | NFSMODE_IRGRP | 1475 NFSMODE_IXUSR | NFSMODE_IWUSR | NFSMODE_IRUSR); 1476 *ptr++ = txdr_unsigned(tmp); 1477 reqlen += sizeof(uint32_t); 1478 1479 /* Set the user ID to zero */ 1480 1481 *ptr++ = nfs_true; /* True: Uid value follows */ 1482 *ptr++ = 0; /* UID = 0 (nobody) */ 1483 reqlen += 2*sizeof(uint32_t); 1484 1485 /* Set the group ID to one */ 1486 1487 *ptr++ = nfs_true; /* True: Gid value follows */ 1488 *ptr++ = htonl(1); /* GID = 1 (nogroup) */ 1489 reqlen += 2*sizeof(uint32_t); 1490 1491 /* No size */ 1492 1493 *ptr++ = nfs_false; /* False: No size value follows */ 1494 reqlen += sizeof(uint32_t); 1495 1496 /* Don't change times */ 1497 1498 *ptr++ = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change atime */ 1499 *ptr++ = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change mtime */ 1500 reqlen += 2*sizeof(uint32_t); 1501 1502 /* Perform the MKDIR RPC */ 1503 1504 nfs_statistics(NFSPROC_MKDIR); 1505 error = nfs_request(nmp, NFSPROC_MKDIR, 1506 (void *)&nmp->nm_msgbuffer.mkdir, reqlen, 1507 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 1508 if (error) 1509 { 1510 nfs_debug_error("nfs_request failed: %d\n", error); 1511 goto errout_with_mutex; 1512 } 1513 1514 fhandle.length = parent_nfs_node->n_fhsize; 1515 memcpy_s(&(fhandle.handle), DIRENT_NFS_MAXHANDLE, &(parent_nfs_node->n_fhandle), fhandle.length); 1516 error = nfs_lookup(nmp, dirname, &fhandle, &obj_attributes, NULL); 1517 if (error) 1518 { 1519 error = ENOENT; 1520 goto errout_with_mutex; 1521 } 1522 1523 /* Initialize the file private data. 1524 * 1525 * Copy the file handle. 1526 */ 1527 target_node = zalloc(sizeof(struct nfsnode)); 1528 target_node->n_fhsize = (uint8_t)fhandle.length; 1529 memcpy_s(&(target_node->n_fhandle), target_node->n_fhsize, &(fhandle.handle), fhandle.length); 1530 target_node->n_pfhsize = parent_nfs_node->n_fhsize; 1531 (void)memcpy_s(&(target_node->n_pfhandle), NFSX_V3FHMAX, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize); 1532 target_node->n_name = zalloc(sizeof (dirname)); 1533 memcpy_s(target_node->n_name, sizeof(dirname), dirname, sizeof (dirname)); 1534 target_node->n_next = nmp->nm_head; 1535 nmp->nm_head = target_node; 1536 1537 /* Save the file attributes */ 1538 nfs_attrupdate(target_node, &obj_attributes); 1539 (void)VnodeAlloc(&nfs_vops, vpp); 1540 (*vpp)->parent = parent; 1541 (*vpp)->fop = &nfs_fops; 1542 (*vpp)->originMount = parent->originMount; 1543 (*vpp)->data = target_node; 1544 (*vpp)->type = filetype_to_vnodetype(target_node->n_type); 1545 (*vpp)->mode = type_to_mode((*vpp)->type, nmp->nm_permission); 1546 (*vpp)->gid = nmp->nm_gid; 1547 (*vpp)->uid = nmp->nm_uid; 1548 1549errout_with_mutex: 1550 nfs_mux_release(nmp); 1551 return -error; 1552} 1553 1554int vfs_nfs_write(struct file *filep, const char *buffer, size_t buflen) 1555{ 1556 struct nfsmount *nmp; 1557 struct nfsnode *np; 1558 loff_t f_pos; 1559 size_t writesize; 1560 size_t bufsize; 1561 size_t byteswritten; 1562 size_t reqlen; 1563 uint32_t *ptr = NULL; 1564 uint32_t tmp; 1565 int committed = NFSV3WRITE_UNSTABLE; 1566 int error; 1567 char *temp_buffer = NULL; 1568 struct file_handle parent_fhandle; 1569 1570 struct Vnode *node = filep->f_vnode; 1571 nmp = (struct nfsmount *)(node->originMount->data); 1572 DEBUGASSERT(nmp != NULL); 1573 1574 /* Make sure that the mount is still healthy */ 1575 1576 nfs_mux_take(nmp); 1577 np = (struct nfsnode *)node->data; 1578 error = nfs_checkmount(nmp); 1579 if (error != OK) 1580 { 1581 nfs_debug_error("nfs_checkmount failed: %d\n", error); 1582 goto errout_with_mutex; 1583 } 1584 1585 parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize; 1586 (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX, 1587 &(((struct nfsnode *)node->data)->n_pfhandle), 1588 ((struct nfsnode *)node->data)->n_pfhsize); 1589 1590 if (filep->f_oflags & O_APPEND) 1591 { 1592 if (nfs_fileupdate(nmp, np->n_name, &parent_fhandle, np) == OK) 1593 { 1594 f_pos = np->n_size; 1595 } 1596 else 1597 { 1598 error = EAGAIN; 1599 goto errout_with_mutex; 1600 } 1601 } 1602 else 1603 { 1604 f_pos = filep->f_pos; 1605 } 1606 1607 /* Check if the file size would exceed the range of off_t */ 1608 1609 if (np->n_size + buflen < np->n_size) 1610 { 1611 error = EFBIG; 1612 goto errout_with_mutex; 1613 } 1614 1615 /* Allocate memory for data */ 1616 1617 bufsize = (buflen < nmp->nm_wsize) ? buflen : nmp->nm_wsize; 1618 temp_buffer = malloc(bufsize); 1619 if (temp_buffer == NULL) 1620 { 1621 error = ENOMEM; 1622 goto errout_with_mutex; 1623 } 1624 1625 /* Now loop until we send the entire user buffer */ 1626 1627 writesize = 0; 1628 for (byteswritten = 0; byteswritten < buflen; ) 1629 { 1630 /* Make sure that the attempted write size does not exceed the RPC 1631 * maximum. 1632 */ 1633 1634 writesize = buflen - byteswritten; 1635 if (writesize > nmp->nm_wsize) 1636 { 1637 writesize = nmp->nm_wsize; 1638 } 1639 1640 /* Make sure that the attempted read size does not exceed the IO 1641 * buffer size. 1642 */ 1643 1644 bufsize = SIZEOF_rpc_call_write(writesize); 1645 if (bufsize > nmp->nm_buflen) 1646 { 1647 writesize -= (bufsize - nmp->nm_buflen); 1648 } 1649 1650 /* Copy a chunk of the user data into the temporary buffer */ 1651 1652 if (LOS_CopyToKernel(temp_buffer, writesize, buffer, writesize) != 0) 1653 { 1654 error = EINVAL; 1655 goto errout_with_memfree; 1656 } 1657 1658 /* Initialize the request. Here we need an offset pointer to the write 1659 * arguments, skipping over the RPC header. Write is unique among the 1660 * RPC calls in that the entry RPC calls messasge lies in the I/O buffer 1661 */ 1662 1663 ptr = (uint32_t *)&((struct rpc_call_write *) 1664 nmp->nm_iobuffer)->write; 1665 reqlen = 0; 1666 1667 /* Copy the variable length, file handle */ 1668 1669 *ptr++ = txdr_unsigned((uint32_t)np->n_fhsize); 1670 reqlen += sizeof(uint32_t); 1671 1672 (void)memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize); 1673 reqlen += (int)np->n_fhsize; 1674 ptr += uint32_increment((int)np->n_fhsize); 1675 1676 /* Copy the file offset */ 1677 1678 txdr_hyper((uint64_t)f_pos, ptr); 1679 ptr += 2; 1680 reqlen += 2*sizeof(uint32_t); 1681 1682 /* Copy the count and stable values */ 1683 1684 *ptr++ = txdr_unsigned(writesize); 1685 *ptr++ = txdr_unsigned((uint32_t)committed); 1686 reqlen += 2*sizeof(uint32_t); 1687 1688 /* Copy a chunk of the user data into the I/O buffer from temporary buffer */ 1689 1690 *ptr++ = txdr_unsigned(writesize); 1691 reqlen += sizeof(uint32_t); 1692 error = memcpy_s(ptr, writesize, temp_buffer, writesize); 1693 if (error != EOK) 1694 { 1695 error = ENOBUFS; 1696 goto errout_with_memfree; 1697 } 1698 reqlen += uint32_alignup(writesize); 1699 1700 /* Perform the write */ 1701 1702 nfs_statistics(NFSPROC_WRITE); 1703 error = nfs_request(nmp, NFSPROC_WRITE, 1704 (void *)nmp->nm_iobuffer, reqlen, 1705 (void *)&nmp->nm_msgbuffer.write, 1706 sizeof(struct rpc_reply_write)); 1707 if (error) 1708 { 1709 goto errout_with_memfree; 1710 } 1711 1712 /* Get a pointer to the WRITE reply data */ 1713 1714 ptr = (uint32_t *)&nmp->nm_msgbuffer.write.write; 1715 1716 /* Parse file_wcc. First, check if WCC attributes follow. */ 1717 1718 tmp = *ptr++; 1719 if (tmp != 0) 1720 { 1721 /* Yes.. WCC attributes follow. But we just skip over them. */ 1722 1723 ptr += uint32_increment(sizeof(struct wcc_attr)); 1724 } 1725 1726 /* Check if normal file attributes follow */ 1727 1728 tmp = *ptr++; 1729 if (tmp != 0) 1730 { 1731 /* Yes.. Update the cached file status in the file structure. */ 1732 1733 nfs_attrupdate(np, (struct nfs_fattr *)ptr); 1734 ptr += uint32_increment(sizeof(struct nfs_fattr)); 1735 } 1736 1737 /* Get the count of bytes actually written */ 1738 1739 tmp = fxdr_unsigned(uint32_t, *ptr); 1740 ptr++; 1741 1742 if (tmp < 1 || tmp > writesize) 1743 { 1744 error = EIO; 1745 goto errout_with_memfree; 1746 } 1747 1748 writesize = tmp; 1749 f_pos += writesize; 1750 filep->f_pos = f_pos; 1751 np->n_fpos = f_pos; 1752 1753 /* Update the read state data */ 1754 1755 if (filep->f_pos > (loff_t)np->n_size) 1756 { 1757 np->n_size = f_pos; 1758 } 1759 byteswritten += writesize; 1760 buffer += writesize; 1761 } 1762 1763 free(temp_buffer); 1764 nfs_mux_release(nmp); 1765 return byteswritten; 1766errout_with_memfree: 1767 free(temp_buffer); 1768errout_with_mutex: 1769 nfs_mux_release(nmp); 1770 return -error; 1771} 1772 1773ssize_t vfs_nfs_writepage(struct Vnode *node, char *buffer, off_t pos, size_t buflen) 1774{ 1775 struct nfsmount *nmp; 1776 struct nfsnode *np; 1777 loff_t f_pos = pos; 1778 size_t writesize; 1779 size_t bufsize; 1780 size_t byteswritten; 1781 size_t reqlen; 1782 uint32_t *ptr = NULL; 1783 uint32_t tmp; 1784 int committed = NFSV3WRITE_UNSTABLE; 1785 int error; 1786 char *temp_buffer = NULL; 1787 struct file_handle parent_fhandle; 1788 1789 nmp = (struct nfsmount *)(node->originMount->data); 1790 DEBUGASSERT(nmp != NULL); 1791 1792 /* Make sure that the mount is still healthy */ 1793 1794 nfs_mux_take(nmp); 1795 np = (struct nfsnode *)node->data; 1796 error = nfs_checkmount(nmp); 1797 if (error != OK) 1798 { 1799 nfs_debug_error("nfs_checkmount failed: %d\n", error); 1800 goto errout_with_mutex; 1801 } 1802 1803 parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize; 1804 (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX, 1805 &(((struct nfsnode *)node->data)->n_pfhandle), 1806 ((struct nfsnode *)node->data)->n_pfhsize); 1807 1808 /* Check if the file size would exceed the range of off_t */ 1809 1810 if (np->n_size + buflen < np->n_size) 1811 { 1812 error = EFBIG; 1813 goto errout_with_mutex; 1814 } 1815 1816 /* writepage cannot exceed the file range */ 1817 1818 if (f_pos >= np->n_size) 1819 { 1820 error = ERANGE; 1821 goto errout_with_mutex; 1822 } 1823 1824 buflen = min(buflen, np->n_size - f_pos); 1825 1826 /* Allocate memory for data */ 1827 1828 bufsize = (buflen < nmp->nm_wsize) ? buflen : nmp->nm_wsize; 1829 temp_buffer = malloc(bufsize); 1830 if (temp_buffer == NULL) 1831 { 1832 error = ENOMEM; 1833 goto errout_with_mutex; 1834 } 1835 1836 /* Now loop until we send the entire user buffer */ 1837 1838 writesize = 0; 1839 for (byteswritten = 0; byteswritten < buflen; ) 1840 { 1841 /* Make sure that the attempted write size does not exceed the RPC 1842 * maximum. 1843 */ 1844 1845 writesize = buflen - byteswritten; 1846 if (writesize > nmp->nm_wsize) 1847 { 1848 writesize = nmp->nm_wsize; 1849 } 1850 1851 /* Make sure that the attempted read size does not exceed the IO 1852 * buffer size. 1853 */ 1854 1855 bufsize = SIZEOF_rpc_call_write(writesize); 1856 if (bufsize > nmp->nm_buflen) 1857 { 1858 writesize -= (bufsize - nmp->nm_buflen); 1859 } 1860 1861 /* Copy a chunk of the user data into the temporary buffer */ 1862 1863 if (LOS_CopyToKernel(temp_buffer, writesize, buffer, writesize) != 0) 1864 { 1865 error = EINVAL; 1866 goto errout_with_memfree; 1867 } 1868 1869 /* Initialize the request. Here we need an offset pointer to the write 1870 * arguments, skipping over the RPC header. Write is unique among the 1871 * RPC calls in that the entry RPC calls messasge lies in the I/O buffer 1872 */ 1873 1874 ptr = (uint32_t *)&((struct rpc_call_write *) 1875 nmp->nm_iobuffer)->write; 1876 reqlen = 0; 1877 1878 /* Copy the variable length, file handle */ 1879 1880 *ptr++ = txdr_unsigned((uint32_t)np->n_fhsize); 1881 reqlen += sizeof(uint32_t); 1882 1883 (void)memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize); 1884 reqlen += (int)np->n_fhsize; 1885 ptr += uint32_increment((int)np->n_fhsize); 1886 1887 /* Copy the file offset */ 1888 1889 txdr_hyper((uint64_t)f_pos, ptr); 1890 ptr += 2; 1891 reqlen += 2*sizeof(uint32_t); 1892 1893 /* Copy the count and stable values */ 1894 1895 *ptr++ = txdr_unsigned(writesize); 1896 *ptr++ = txdr_unsigned((uint32_t)committed); 1897 reqlen += 2*sizeof(uint32_t); 1898 1899 /* Copy a chunk of the user data into the I/O buffer from temporary buffer */ 1900 1901 *ptr++ = txdr_unsigned(writesize); 1902 reqlen += sizeof(uint32_t); 1903 error = memcpy_s(ptr, writesize, temp_buffer, writesize); 1904 if (error != EOK) 1905 { 1906 error = ENOBUFS; 1907 goto errout_with_memfree; 1908 } 1909 reqlen += uint32_alignup(writesize); 1910 1911 /* Perform the write */ 1912 1913 nfs_statistics(NFSPROC_WRITE); 1914 error = nfs_request(nmp, NFSPROC_WRITE, 1915 (void *)nmp->nm_iobuffer, reqlen, 1916 (void *)&nmp->nm_msgbuffer.write, 1917 sizeof(struct rpc_reply_write)); 1918 if (error) 1919 { 1920 goto errout_with_memfree; 1921 } 1922 1923 /* Get a pointer to the WRITE reply data */ 1924 1925 ptr = (uint32_t *)&nmp->nm_msgbuffer.write.write; 1926 1927 /* Parse file_wcc. First, check if WCC attributes follow. */ 1928 1929 tmp = *ptr++; 1930 if (tmp != 0) 1931 { 1932 /* Yes.. WCC attributes follow. But we just skip over them. */ 1933 1934 ptr += uint32_increment(sizeof(struct wcc_attr)); 1935 } 1936 1937 /* Check if normal file attributes follow */ 1938 1939 tmp = *ptr++; 1940 if (tmp != 0) 1941 { 1942 /* Yes.. Update the cached file status in the file structure. */ 1943 1944 nfs_attrupdate(np, (struct nfs_fattr *)ptr); 1945 ptr += uint32_increment(sizeof(struct nfs_fattr)); 1946 } 1947 1948 /* Get the count of bytes actually written */ 1949 1950 tmp = fxdr_unsigned(uint32_t, *ptr); 1951 ptr++; 1952 1953 if (tmp < 1 || tmp > writesize) 1954 { 1955 error = EIO; 1956 goto errout_with_memfree; 1957 } 1958 1959 writesize = tmp; 1960 f_pos += writesize; 1961 np->n_fpos = f_pos; 1962 1963 byteswritten += writesize; 1964 buffer += writesize; 1965 } 1966 1967 free(temp_buffer); 1968 nfs_mux_release(nmp); 1969 return byteswritten; 1970errout_with_memfree: 1971 free(temp_buffer); 1972errout_with_mutex: 1973 nfs_mux_release(nmp); 1974 return -error; 1975} 1976 1977off_t vfs_nfs_seek(struct file *filep, off_t offset, int whence) 1978{ 1979 struct Vnode *node = filep->f_vnode; 1980 struct nfsnode *np = NULL; 1981 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 1982 int error; 1983 off_t position; 1984 1985 /* Make sure that the mount is still healthy */ 1986 1987 nfs_mux_take(nmp); 1988 np = (struct nfsnode *)node->data; 1989 error = nfs_checkmount(nmp); 1990 if (error != OK) 1991 { 1992 nfs_debug_info("nfs_checkmount failed: %d\n", error); 1993 goto errout_with_mutex; 1994 } 1995 1996 1997 switch (whence) 1998 { 1999 case SEEK_SET: /* The offset is set to offset bytes. */ 2000 position = offset; 2001 break; 2002 2003 case SEEK_CUR: /* The offset is set to its current location plus offset bytes. */ 2004 position = offset + filep->f_pos; 2005 break; 2006 2007 case SEEK_END: /* The offset is set to the size of the file plus offset bytes. */ 2008 position = offset + np->n_size; 2009 break; 2010 2011 default: 2012 error = EINVAL; 2013 goto errout_with_mutex; 2014 } 2015 2016 /* Attempts to set the position beyound the end of file will 2017 * work if the file is open for write access. 2018 */ 2019 2020 if ((position > (off_t)np->n_size) && ((np->n_oflags & O_WRONLY) == 0) && 2021 ((np->n_oflags & O_RDWR) == 0)) 2022 { 2023 position = np->n_size; 2024 } 2025 2026 /* position less than 0 should be reset to 0 */ 2027 2028 if (position < 0) 2029 { 2030 position = 0; 2031 } 2032 2033 np->n_fpos = (loff_t)position; 2034 filep->f_pos = np->n_fpos; 2035 if (position > (off_t)np->n_size) 2036 { 2037 np->n_size = (loff_t)position; 2038 } 2039 nfs_mux_release(nmp); 2040 return (off_t)filep->f_pos; 2041 2042errout_with_mutex: 2043 nfs_mux_release(nmp); 2044 return -error; 2045} 2046 2047ssize_t vfs_nfs_readpage(struct Vnode *node, char *buffer, off_t pos) 2048{ 2049 struct nfsnode *np; 2050 struct rpc_reply_read *read_response = NULL; 2051 size_t readsize; 2052 size_t tmp; 2053 size_t bytesread; 2054 size_t reqlen; 2055 uint32_t *ptr = NULL; 2056 int error = 0; 2057 struct file_handle parent_fhandle; 2058 int buflen = PAGE_SIZE; 2059 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 2060 2061 DEBUGASSERT(nmp != NULL); 2062 2063 /* Make sure that the mount is still healthy */ 2064 2065 nfs_mux_take(nmp); 2066 np = (struct nfsnode *)node->data; 2067 error = nfs_checkmount(nmp); 2068 if (error != OK) 2069 { 2070 nfs_debug_error("nfs_checkmount failed: %d\n", error); 2071 goto errout_with_mutex; 2072 } 2073 2074 2075 parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize; 2076 (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX, 2077 &(((struct nfsnode *)node->data)->n_pfhandle), 2078 ((struct nfsnode *)node->data)->n_pfhsize); 2079 error = nfs_fileupdate(nmp, np->n_name, &parent_fhandle, np); 2080 if (error != OK) 2081 { 2082 nfs_debug_info("nfs_fileupdate failed: %d\n", error); 2083 goto errout_with_mutex; 2084 } 2085 2086 /* Get the number of bytes left in the file and truncate read count so that 2087 * it does not exceed the number of bytes left in the file. 2088 */ 2089 2090 if (pos >= np->n_size) { 2091 error = EFAULT; 2092 nfs_debug_info("readpage out of file range: %d\n", error); 2093 goto errout_with_mutex; 2094 } 2095 2096 tmp = np->n_size - pos; 2097 if (buflen > tmp) 2098 { 2099 buflen = tmp; 2100 } 2101 2102 /* Now loop until we fill the user buffer (or hit the end of the file) */ 2103 2104 for (bytesread = 0; bytesread < buflen; ) 2105 { 2106 /* Make sure that the attempted read size does not exceed the RPC maximum */ 2107 2108 readsize = buflen - bytesread; 2109 if (readsize > nmp->nm_rsize) 2110 { 2111 readsize = nmp->nm_rsize; 2112 } 2113 2114 /* Make sure that the attempted read size does not exceed the IO buffer size */ 2115 2116 tmp = SIZEOF_rpc_reply_read(readsize); 2117 if (tmp > nmp->nm_buflen) 2118 { 2119 readsize -= (tmp - nmp->nm_buflen); 2120 } 2121 2122 /* Initialize the request */ 2123 2124 ptr = (uint32_t *)&nmp->nm_msgbuffer.read.read; 2125 reqlen = 0; 2126 2127 /* Copy the variable length, file handle */ 2128 2129 *ptr++ = txdr_unsigned((uint32_t)np->n_fhsize); 2130 reqlen += sizeof(uint32_t); 2131 2132 memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize); 2133 reqlen += (int)np->n_fhsize; 2134 ptr += uint32_increment((int)np->n_fhsize); 2135 2136 /* Copy the file offset */ 2137 2138 txdr_hyper((uint64_t)pos, ptr); 2139 ptr += 2; 2140 reqlen += 2*sizeof(uint32_t); 2141 2142 /* Set the readsize */ 2143 2144 *ptr = txdr_unsigned(readsize); 2145 reqlen += sizeof(uint32_t); 2146 2147 /* Perform the read */ 2148 2149 nfs_statistics(NFSPROC_READ); 2150 error = nfs_request(nmp, NFSPROC_READ, 2151 (void *)&nmp->nm_msgbuffer.read, reqlen, 2152 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2153 if (error) 2154 { 2155 nfs_debug_error("nfs_request failed: %d\n", error); 2156 goto errout_with_mutex; 2157 } 2158 2159 /* The read was successful. Get a pointer to the beginning of the NFS 2160 * response data. 2161 */ 2162 2163 read_response = (struct rpc_reply_read *)nmp->nm_iobuffer; 2164 readsize = fxdr_unsigned(uint32_t, read_response->read.hdr.count); 2165 2166 /* Copy the read data into the user buffer */ 2167 2168 if (LOS_CopyFromKernel(buffer, buflen, (const void *)read_response->read.data, readsize) != 0) 2169 { 2170 error = EINVAL; 2171 goto errout_with_mutex; 2172 } 2173 2174 /* Update the read state data */ 2175 2176 pos += readsize; 2177 np->n_fpos += readsize; 2178 bytesread += readsize; 2179 buffer += readsize; 2180 2181 /* Check if we hit the end of file */ 2182 2183 if (read_response->read.hdr.eof != 0) 2184 { 2185 break; 2186 } 2187 } 2188 2189 nfs_mux_release(nmp); 2190 return bytesread; 2191 2192errout_with_mutex: 2193 nfs_mux_release(nmp); 2194 return -error; 2195} 2196 2197ssize_t vfs_nfs_read(struct file *filep, char *buffer, size_t buflen) 2198{ 2199 struct nfsnode *np; 2200 struct rpc_reply_read *read_response = NULL; 2201 size_t readsize; 2202 size_t tmp; 2203 size_t bytesread; 2204 size_t reqlen; 2205 uint32_t *ptr = NULL; 2206 int error = 0; 2207 struct file_handle parent_fhandle; 2208 2209 struct Vnode *node = filep->f_vnode; 2210 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 2211 2212 DEBUGASSERT(nmp != NULL); 2213 2214 /* Make sure that the mount is still healthy */ 2215 2216 nfs_mux_take(nmp); 2217 np = (struct nfsnode *)node->data; 2218 error = nfs_checkmount(nmp); 2219 if (error != OK) 2220 { 2221 nfs_debug_error("nfs_checkmount failed: %d\n", error); 2222 goto errout_with_mutex; 2223 } 2224 2225 2226 parent_fhandle.length = ((struct nfsnode *)node->data)->n_pfhsize; 2227 (void)memcpy_s(&(parent_fhandle.handle), NFSX_V3FHMAX, 2228 &(((struct nfsnode *)node->data)->n_pfhandle), 2229 ((struct nfsnode *)node->data)->n_pfhsize); 2230 error = nfs_fileupdate(nmp, np->n_name, &parent_fhandle, np); 2231 if (error != OK) 2232 { 2233 nfs_debug_info("nfs_fileupdate failed: %d\n", error); 2234 goto errout_with_mutex; 2235 } 2236 2237 /* Get the number of bytes left in the file and truncate read count so that 2238 * it does not exceed the number of bytes left in the file. 2239 */ 2240 2241 tmp = np->n_size - filep->f_pos; 2242 if (buflen > tmp) 2243 { 2244 buflen = tmp; 2245 } 2246 2247 /* Now loop until we fill the user buffer (or hit the end of the file) */ 2248 2249 for (bytesread = 0; bytesread < buflen; ) 2250 { 2251 /* Make sure that the attempted read size does not exceed the RPC maximum */ 2252 2253 readsize = buflen - bytesread; 2254 if (readsize > nmp->nm_rsize) 2255 { 2256 readsize = nmp->nm_rsize; 2257 } 2258 2259 /* Make sure that the attempted read size does not exceed the IO buffer size */ 2260 2261 tmp = SIZEOF_rpc_reply_read(readsize); 2262 if (tmp > nmp->nm_buflen) 2263 { 2264 readsize -= (tmp - nmp->nm_buflen); 2265 } 2266 2267 /* Initialize the request */ 2268 2269 ptr = (uint32_t *)&nmp->nm_msgbuffer.read.read; 2270 reqlen = 0; 2271 2272 /* Copy the variable length, file handle */ 2273 2274 *ptr++ = txdr_unsigned((uint32_t)np->n_fhsize); 2275 reqlen += sizeof(uint32_t); 2276 2277 memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize); 2278 reqlen += (int)np->n_fhsize; 2279 ptr += uint32_increment((int)np->n_fhsize); 2280 2281 /* Copy the file offset */ 2282 2283 txdr_hyper((uint64_t)filep->f_pos, ptr); 2284 ptr += 2; 2285 reqlen += 2*sizeof(uint32_t); 2286 2287 /* Set the readsize */ 2288 2289 *ptr = txdr_unsigned(readsize); 2290 reqlen += sizeof(uint32_t); 2291 2292 /* Perform the read */ 2293 2294 nfs_statistics(NFSPROC_READ); 2295 error = nfs_request(nmp, NFSPROC_READ, 2296 (void *)&nmp->nm_msgbuffer.read, reqlen, 2297 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2298 if (error) 2299 { 2300 nfs_debug_error("nfs_request failed: %d\n", error); 2301 goto errout_with_mutex; 2302 } 2303 2304 /* The read was successful. Get a pointer to the beginning of the NFS 2305 * response data. 2306 */ 2307 2308 read_response = (struct rpc_reply_read *)nmp->nm_iobuffer; 2309 readsize = fxdr_unsigned(uint32_t, read_response->read.hdr.count); 2310 2311 /* Copy the read data into the user buffer */ 2312 2313 if (LOS_CopyFromKernel(buffer, buflen, (const void *)read_response->read.data, readsize) != 0) 2314 { 2315 error = EINVAL; 2316 goto errout_with_mutex; 2317 } 2318 2319 /* Update the read state data */ 2320 2321 filep->f_pos += readsize; 2322 np->n_fpos += readsize; 2323 bytesread += readsize; 2324 buffer += readsize; 2325 2326 /* Check if we hit the end of file */ 2327 2328 if (read_response->read.hdr.eof != 0) 2329 { 2330 break; 2331 } 2332 } 2333 2334 nfs_mux_release(nmp); 2335 return bytesread; 2336 2337errout_with_mutex: 2338 nfs_mux_release(nmp); 2339 return -error; 2340} 2341 2342int vfs_nfs_create(struct Vnode *parent, const char *filename, int mode, struct Vnode **vpp) 2343{ 2344 uint32_t *ptr = NULL; 2345 uint32_t tmp; 2346 int namelen; 2347 int reqlen; 2348 int error; 2349 struct nfsnode *parent_nfs_node = (struct nfsnode *)parent->data; 2350 struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data); 2351 struct nfsnode *np = zalloc(sizeof(struct nfsnode)); 2352 nfs_mux_take(nmp); 2353 error = nfs_checkmount(nmp); 2354 if (error != OK) 2355 { 2356 nfs_debug_error("nfs_checkmount failed: %d\n", error); 2357 goto errout_with_mutex; 2358 } 2359 ptr = (uint32_t *)&nmp->nm_msgbuffer.create.create; 2360 reqlen = 0; 2361 2362 /* Copy the variable length, directory file handle */ 2363 2364 *ptr++ = txdr_unsigned(parent_nfs_node->n_fhsize); 2365 reqlen += sizeof(uint32_t); 2366 2367 (void)memcpy_s(ptr, parent_nfs_node->n_fhsize, &parent_nfs_node->n_fhandle, parent_nfs_node->n_fhsize); 2368 reqlen += (int)parent_nfs_node->n_fhsize; 2369 ptr += uint32_increment(parent_nfs_node->n_fhsize); 2370 2371 /* Copy the variable-length file name */ 2372 2373 namelen = strlen(filename); 2374 2375 *ptr++ = txdr_unsigned(namelen); 2376 reqlen += sizeof(uint32_t); 2377 2378 (void)memcpy_s(ptr, namelen, filename, namelen); 2379 ptr += uint32_increment(namelen); 2380 reqlen += uint32_alignup(namelen); 2381 2382 /* Set the creation mode */ 2383 2384#ifdef USE_GUARDED_CREATE 2385 *ptr++ = htonl(NFSV3CREATE_GUARDED); 2386#else 2387 *ptr++ = htonl(NFSV3CREATE_EXCLUSIVE); 2388#endif 2389 2390 reqlen += sizeof(uint32_t); 2391 2392 /* Mode information is not provided if EXCLUSIVE creation is used. 2393 * in this case, we must call SETATTR after successfully creating 2394 * the file. 2395 */ 2396 2397 /* Set the mode. NOTE: Here we depend on the fact that the NuttX and NFS 2398 * bit settings are the same (at least for the bits of interest). 2399 */ 2400 2401 *ptr++ = nfs_true; /* True: mode value follows */ 2402 reqlen += sizeof(uint32_t); 2403 2404 tmp = mode & (NFSMODE_IWOTH | NFSMODE_IROTH | NFSMODE_IWGRP | 2405 NFSMODE_IRGRP | NFSMODE_IWUSR | NFSMODE_IRUSR); 2406 *ptr++ = txdr_unsigned(tmp); 2407 reqlen += sizeof(uint32_t); 2408 2409 /* Set the user ID to zero */ 2410 2411 *ptr++ = nfs_true; /* True: Uid value follows */ 2412 *ptr++ = 0; /* UID = 0 (nobody) */ 2413 reqlen += 2*sizeof(uint32_t); 2414 2415 /* Set the group ID to one */ 2416 2417 *ptr++ = nfs_true; /* True: Gid value follows */ 2418 *ptr++ = htonl(1); /* GID = 1 (nogroup) */ 2419 reqlen += 2*sizeof(uint32_t); 2420 2421 /* Set the size to zero */ 2422 2423 *ptr++ = nfs_true; /* True: Size value follows */ 2424 *ptr++ = 0; /* Size = 0 */ 2425 *ptr++ = 0; 2426 reqlen += 3*sizeof(uint32_t); 2427 2428 /* Don't change times */ 2429 2430 *ptr++ = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change atime */ 2431 *ptr++ = htonl(NFSV3SATTRTIME_DONTCHANGE); /* Don't change mtime */ 2432 reqlen += 2*sizeof(uint32_t); 2433 2434 /* Send the NFS request. Note there is special logic here to handle version 3 2435 * exclusive open semantics. 2436 */ 2437 2438 do 2439 { 2440 nfs_statistics(NFSPROC_CREATE); 2441 error = nfs_request(nmp, NFSPROC_CREATE, 2442 (void *)&nmp->nm_msgbuffer.create, reqlen, 2443 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2444 } 2445 while (0); 2446 2447 /* Check for success */ 2448 2449 if (error != OK) 2450 { 2451 *vpp = NULL; 2452 goto errout_with_mutex; 2453 } 2454 2455 /* Parse the returned data */ 2456 2457 ptr = (uint32_t *)&((struct rpc_reply_create *) 2458 nmp->nm_iobuffer)->create; 2459 2460 /* Save the file handle in the file data structure */ 2461 2462 tmp = *ptr++; /* handle_follows */ 2463 if (!tmp) 2464 { 2465 nfs_debug_error("no file handle follows\n"); 2466 error = EINVAL; 2467 goto errout_with_mutex; 2468 } 2469 2470 tmp = *ptr++; 2471 tmp = fxdr_unsigned(uint32_t, tmp); 2472 DEBUGASSERT(tmp <= NFSX_V3FHMAX); 2473 2474 np->n_fhsize = (uint8_t)tmp; 2475 (void)memcpy_s(&np->n_fhandle, tmp, ptr, tmp); 2476 ptr += uint32_increment(tmp); 2477 2478 /* Save the attributes in the file data structure */ 2479 2480 tmp = *ptr; /* handle_follows */ 2481 if (!tmp) 2482 { 2483 nfs_debug_info("WARNING: no file attributes\n"); 2484 } 2485 else 2486 { 2487 /* Initialize the file attributes */ 2488 2489 nfs_attrupdate(np, (struct nfs_fattr *)ptr); 2490 } 2491 2492 /* Any following dir_wcc data is ignored for now */ 2493 np->n_crefs = 1; 2494 2495 /* Attach the private data to the struct file instance */ 2496 2497 /* Then insert the new instance at the head of the list in the mountpoint 2498 * tructure. It needs to be there (1) to handle error conditions that effect 2499 * all files, and (2) to inform the umount logic that we are busy. We 2500 * cannot unmount the file system if this list is not empty! 2501 */ 2502 2503 np->n_next = nmp->nm_head; 2504 nmp->nm_head = np; 2505 2506 np->n_pfhsize = parent_nfs_node->n_fhsize; 2507 (void)memcpy_s(&(np->n_pfhandle), NFSX_V3FHMAX, &(parent_nfs_node->n_fhandle), parent_nfs_node->n_fhsize); 2508 2509 np->n_flags |= (NFSNODE_OPEN | NFSNODE_MODIFIED); 2510 np->n_name = zalloc(namelen + 1); 2511 memcpy_s(np->n_name, (namelen + 1), filename, (namelen + 1)); 2512 2513 (void)VnodeAlloc(&nfs_vops, vpp); 2514 (*vpp)->parent = parent; 2515 (*vpp)->fop = &nfs_fops; 2516 (*vpp)->originMount = parent->originMount; 2517 (*vpp)->data = np; 2518 (*vpp)->type = filetype_to_vnodetype(np->n_type); 2519 (*vpp)->mode = type_to_mode((*vpp)->type, nmp->nm_permission); 2520 (*vpp)->gid = nmp->nm_gid; 2521 (*vpp)->uid = nmp->nm_uid; 2522 2523 nfs_mux_release(nmp); 2524 return OK; 2525 2526errout_with_mutex: 2527 if (np) 2528 { 2529 free(np); 2530 } 2531 nfs_mux_release(nmp); 2532 return -error; 2533} 2534 2535int vfs_nfs_unlink(struct Vnode *parent, struct Vnode *target, const char *filename) 2536{ 2537 struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data); 2538 struct nfsnode *parent_node = NULL; 2539 struct nfsnode *target_node = NULL; 2540 int reqlen; 2541 int namelen; 2542 uint32_t *ptr = NULL; 2543 int error; 2544 2545 nfs_mux_take(nmp); 2546 error = nfs_checkmount(nmp); 2547 if (error != OK) 2548 { 2549 nfs_debug_error("nfs_checkmount failed: %d\n", error); 2550 goto errout_with_mutex; 2551 } 2552 2553 parent_node = (struct nfsnode*)(parent->data); 2554 target_node = (struct nfsnode*)(target->data); 2555 2556 if (target_node->n_type == NFDIR) 2557 { 2558 nfs_debug_error("try to remove a directory\n"); 2559 error = EISDIR; 2560 goto errout_with_mutex; 2561 } 2562 2563 /* Create the REMOVE RPC call arguments */ 2564 2565 ptr = (uint32_t *)&nmp->nm_msgbuffer.removef.remove; 2566 reqlen = 0; 2567 2568 /* Copy the variable length, directory file handle */ 2569 2570 *ptr++ = txdr_unsigned(parent_node->n_fhsize); 2571 reqlen += sizeof(uint32_t); 2572 2573 (void)memcpy_s(ptr, parent_node->n_fhsize, &parent_node->n_fhandle, parent_node->n_fhsize); 2574 reqlen += (int)parent_node->n_fhsize; 2575 ptr += uint32_increment(parent_node->n_fhsize); 2576 2577 /* Copy the variable-length file name */ 2578 2579 namelen = strlen(filename); 2580 2581 *ptr++ = txdr_unsigned(namelen); 2582 reqlen += sizeof(uint32_t); 2583 2584 (void)memcpy_s(ptr, namelen, filename, namelen); 2585 reqlen += uint32_alignup(namelen); 2586 2587 /* Perform the REMOVE RPC call */ 2588 2589 nfs_statistics(NFSPROC_REMOVE); 2590 error = nfs_request(nmp, NFSPROC_REMOVE, 2591 (void *)&nmp->nm_msgbuffer.removef, reqlen, 2592 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2593 2594errout_with_mutex: 2595 nfs_mux_release(nmp); 2596 return -error; 2597} 2598 2599int vfs_nfs_rmdir(struct Vnode *parent, struct Vnode *target, const char *dirname) 2600{ 2601 struct nfsmount *nmp = (struct nfsmount *)(parent->originMount->data); 2602 struct nfsnode *parent_node = NULL; 2603 struct nfsnode *target_node = NULL; 2604 int reqlen; 2605 int namelen; 2606 uint32_t *ptr = NULL; 2607 int error; 2608 nfs_mux_take(nmp); 2609 error = nfs_checkmount(nmp); 2610 if (error != OK) 2611 { 2612 nfs_debug_error("nfs_checkmount failed: %d\n", error); 2613 goto errout_with_mutex; 2614 } 2615 2616 parent_node = (struct nfsnode*)(parent->data); 2617 target_node = (struct nfsnode*)(target->data); 2618 2619 if (target_node->n_type != NFDIR) 2620 { 2621 nfs_debug_error("try to remove a non-dir\n"); 2622 return -ENOTDIR; 2623 } 2624 2625 /* Set up the RMDIR call message arguments */ 2626 2627 ptr = (uint32_t *)&nmp->nm_msgbuffer.rmdir.rmdir; 2628 reqlen = 0; 2629 2630 /* Copy the variable length, directory file handle */ 2631 2632 *ptr++ = txdr_unsigned(parent_node->n_fhsize); 2633 reqlen += sizeof(uint32_t); 2634 2635 (void)memcpy_s(ptr, parent_node->n_fhsize, &parent_node->n_fhandle, parent_node->n_fhsize); 2636 reqlen += (int)parent_node->n_fhsize; 2637 ptr += uint32_increment(parent_node->n_fhsize); 2638 2639 /* Copy the variable-length directory name */ 2640 2641 namelen = strlen(dirname); 2642 2643 *ptr++ = txdr_unsigned(namelen); 2644 reqlen += sizeof(uint32_t); 2645 2646 (void)memcpy_s(ptr, namelen, dirname, namelen); 2647 reqlen += uint32_alignup(namelen); 2648 2649 /* Perform the RMDIR RPC */ 2650 2651 nfs_statistics(NFSPROC_RMDIR); 2652 error = nfs_request(nmp, NFSPROC_RMDIR, 2653 (void *)&nmp->nm_msgbuffer.rmdir, reqlen, 2654 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2655 2656errout_with_mutex: 2657 nfs_mux_release(nmp); 2658 return -nfs_2_vfs(error); 2659} 2660 2661 2662int vfs_nfs_close(struct Vnode *node) 2663{ 2664 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 2665 struct nfsnode *np = NULL; 2666 nfs_mux_take(nmp); 2667 np = (struct nfsnode*)(node->data); 2668 /* Decrement the reference count. If the reference count would not 2669 * decrement to zero, then that is all we have to do. 2670 */ 2671 2672 if (np->n_crefs > 1) 2673 { 2674 np->n_crefs--; 2675 } 2676 nfs_mux_release(nmp); 2677 return OK; 2678} 2679 2680int vfs_nfs_close_file(struct file *filep) 2681{ 2682 struct Vnode *node = (struct Vnode *)filep->f_vnode; 2683 return vfs_nfs_close(node); 2684} 2685 2686int vfs_nfs_closedir(struct Vnode *node, struct fs_dirent_s *dir) 2687{ 2688 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 2689 struct nfsdir_s *prev = NULL; 2690 struct nfsdir_s *curr = NULL; 2691 struct nfsdir_s *nfs_dir; 2692 struct entry3 *entry_pos = NULL; 2693 int ret; 2694 2695 /* Sanity checks */ 2696 nfs_dir = (struct nfsdir_s *)(dir->u.fs_dir); 2697 2698 DEBUGASSERT(nmp != NULL); 2699 2700 /* Get exclusive access to the mount structure. */ 2701 nfs_mux_take(nmp); 2702 2703 2704 for (entry_pos = nfs_dir->nfs_entries; entry_pos != NULL; entry_pos = nfs_dir->nfs_entries) 2705 { 2706 nfs_dir->nfs_entries = entry_pos->next; 2707 NFS_DIR_ENTRY_FREE(entry_pos); 2708 } 2709 2710 /* Assume file structure will not be found. This should never happen. */ 2711 2712 ret = EINVAL; 2713 2714 for (prev = (struct nfsdir_s *)NULL, curr = nmp->nm_dir; 2715 curr; 2716 prev = curr, curr = curr->nfs_next) 2717 { 2718 /* Check if this node is ours */ 2719 2720 if (nfs_dir == curr) 2721 { 2722 /* Yes.. remove it from the list of file structures */ 2723 2724 if (prev) 2725 { 2726 /* Remove from mid-list */ 2727 2728 prev->nfs_next = nfs_dir->nfs_next; 2729 } 2730 else 2731 { 2732 /* Remove from the head of the list */ 2733 2734 nmp->nm_dir= nfs_dir->nfs_next; 2735 } 2736 2737 /* Then deallocate the file structure and return success */ 2738 2739 free(nfs_dir); 2740 nfs_dir = NULL; 2741 ret = OK; 2742 break; 2743 } 2744 } 2745 nfs_mux_release(nmp); 2746 2747 return -ret; /*lint !e438*/ 2748} 2749 2750/**************************************************************************** 2751 * Name: nfs_fsinfo 2752 * 2753 * Description: 2754 * Return information about root directory. 2755 * 2756 * Returned Value: 2757 * 0 on success; positive errno value on failure 2758 * 2759 * Assumptions: 2760 * The caller has exclusive access to the NFS mount structure 2761 * 2762 ****************************************************************************/ 2763 2764int nfs_fsinfo(struct nfsmount *nmp) 2765{ 2766 struct rpc_call_fs fsinfo; 2767 struct rpc_reply_fsinfo fsp; 2768 struct nfs_fsinfo *rep_info = NULL; 2769 uint32_t pref; 2770 uint32_t max; 2771 int error = 0; 2772 2773 fsinfo.fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize); 2774 fsinfo.fs.fsroot.handle = nmp->nm_fh; 2775 2776 /* Request FSINFO from the server */ 2777 2778 nfs_statistics(NFSPROC_FSINFO); 2779 error = nfs_request(nmp, NFSPROC_FSINFO, 2780 (void *)&fsinfo, sizeof(struct FS3args), 2781 (void *)&fsp, sizeof(struct rpc_reply_fsinfo)); 2782 if (error) 2783 { 2784 return error; 2785 } 2786 2787 if (txdr_unsigned(fsp.fsinfo.obj_attributes.obj_attribute_follow) == 1) 2788 { 2789 rep_info = (struct nfs_fsinfo *)&fsp.fsinfo.fs_rtmax; 2790 } 2791 else 2792 { 2793 rep_info = (struct nfs_fsinfo *)((void *)(&fsp.fsinfo.obj_attributes.attributes)); 2794 } 2795 2796 /* Save the root file system attributes */ 2797 pref = fxdr_unsigned(uint32_t, rep_info->fs_wtpref); 2798 if (pref < nmp->nm_wsize) 2799 { 2800 nmp->nm_wsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1); 2801 } 2802 2803 max = fxdr_unsigned(uint32_t, rep_info->fs_wtmax); 2804 if (max < nmp->nm_wsize) 2805 { 2806 nmp->nm_wsize = max & ~(NFS_FABLKSIZE - 1); 2807 if (nmp->nm_wsize == 0) 2808 { 2809 nmp->nm_wsize = max; 2810 } 2811 } 2812 2813 pref = fxdr_unsigned(uint32_t, rep_info->fs_rtpref); 2814 if (pref < nmp->nm_rsize) 2815 { 2816 nmp->nm_rsize = (pref + NFS_FABLKSIZE - 1) & ~(NFS_FABLKSIZE - 1); 2817 } 2818 2819 max = fxdr_unsigned(uint32_t, rep_info->fs_rtmax); 2820 if (max < nmp->nm_rsize) 2821 { 2822 nmp->nm_rsize = max & ~(NFS_FABLKSIZE - 1); 2823 if (nmp->nm_rsize == 0) 2824 { 2825 nmp->nm_rsize = max; 2826 } 2827 } 2828 2829 pref = fxdr_unsigned(uint32_t, rep_info->fs_dtpref); 2830 if (pref < nmp->nm_readdirsize) 2831 { 2832 nmp->nm_readdirsize = (pref + NFS_DIRBLKSIZ - 1) & ~(NFS_DIRBLKSIZ - 1); 2833 } 2834 2835 if (max < nmp->nm_readdirsize) 2836 { 2837 nmp->nm_readdirsize = max & ~(NFS_DIRBLKSIZ - 1); 2838 if (nmp->nm_readdirsize == 0) 2839 { 2840 nmp->nm_readdirsize = max; 2841 } 2842 } 2843 2844 return OK; 2845} 2846 2847int vfs_nfs_statfs(struct Mount *mountpt, struct statfs *sbp) 2848{ 2849 struct nfsmount *nmp; 2850 struct rpc_call_fs *fsstat = NULL; 2851 struct rpc_reply_fsstat *sfp = NULL; 2852 struct nfs_statfs_ctx *stfp = NULL; 2853 int error = 0; 2854 uint64_t tquad; 2855 2856 /* Get the mountpoint private data from the vnode structure */ 2857 2858 nmp = (struct nfsmount *)mountpt->data; 2859 2860 /* Check if the mount is still healthy */ 2861 2862 nfs_mux_take(nmp); 2863 error = nfs_checkmount(nmp); 2864 if (error != OK) 2865 { 2866 nfs_debug_error("nfs_checkmount failed: %d\n", error); 2867 goto errout_with_mutex; 2868 } 2869 2870 /* Fill in the statfs info */ 2871 2872 sbp->f_type = NFS_SUPER_MAGIC; 2873 2874 error = nfs_fsinfo(nmp); 2875 if (error) 2876 { 2877 nfs_debug_error("nfs_fsinfo failed: %d\n", error); 2878 goto errout_with_mutex; 2879 } 2880 2881 fsstat = &nmp->nm_msgbuffer.fsstat; 2882 fsstat->fs.fsroot.length = txdr_unsigned(nmp->nm_fhsize); 2883 (void)memcpy_s(&fsstat->fs.fsroot.handle, sizeof(nfsfh_t), &nmp->nm_fh, sizeof(nfsfh_t)); 2884 2885 nfs_statistics(NFSPROC_FSSTAT); 2886 error = nfs_request(nmp, NFSPROC_FSSTAT, 2887 (void *)fsstat, sizeof(struct FS3args), 2888 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2889 if (error) 2890 { 2891 goto errout_with_mutex; 2892 } 2893 2894 sfp = (struct rpc_reply_fsstat *)nmp->nm_iobuffer; 2895 if (txdr_unsigned(sfp->fsstat.attributes_follow) == 1) 2896 { 2897 stfp = (struct nfs_statfs_ctx *)&sfp->fsstat.sf_tbytes; 2898 } 2899 else 2900 { 2901 stfp = (struct nfs_statfs_ctx *)&sfp->fsstat.obj_attributes; 2902 } 2903 2904 sbp->f_bsize = NFS_FABLKSIZE; 2905 tquad = fxdr_hyper(&stfp->sf_tbytes); /*lint !e571*/ 2906 sbp->f_blocks = tquad / (uint64_t) NFS_FABLKSIZE; 2907 tquad = fxdr_hyper(&stfp->sf_fbytes); /*lint !e571*/ 2908 sbp->f_bfree = tquad / (uint64_t) NFS_FABLKSIZE; 2909 tquad = fxdr_hyper(&stfp->sf_abytes); /*lint !e571*/ 2910 sbp->f_bavail = tquad / (uint64_t) NFS_FABLKSIZE; 2911 tquad = fxdr_hyper(&stfp->sf_tfiles); /*lint !e571*/ 2912 sbp->f_files = tquad; 2913 tquad = fxdr_hyper(&stfp->sf_ffiles); /*lint !e571*/ 2914 sbp->f_ffree = tquad; 2915 sbp->f_namelen = NAME_MAX; 2916 sbp->f_flags = mountpt->mountFlags; 2917 2918errout_with_mutex: 2919 nfs_mux_release(nmp); 2920 return -error; 2921} 2922 2923static int vfs_nfs_rewinddir(struct Vnode *node, struct fs_dirent_s *dir) 2924{ 2925 struct nfsdir_s *nfs_dir = NULL; 2926 struct entry3 *entry_pos = NULL; 2927 2928 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 2929 nfs_mux_take(nmp); 2930 /* Reset the NFS-specific portions of dirent structure, retaining only the 2931 * file handle. 2932 */ 2933 2934 nfs_dir = (struct nfsdir_s *)dir->u.fs_dir; 2935 (void)memset_s(nfs_dir->nfs_verifier, DIRENT_NFS_VERFLEN, 0, DIRENT_NFS_VERFLEN); 2936 nfs_dir->nfs_cookie[0] = 0; 2937 nfs_dir->nfs_cookie[1] = 0; 2938 for (entry_pos = nfs_dir->nfs_entries; entry_pos != NULL; entry_pos = nfs_dir->nfs_entries) 2939 { 2940 nfs_dir->nfs_entries = entry_pos->next; 2941 NFS_DIR_ENTRY_FREE(entry_pos); 2942 } 2943 free(nfs_dir->nfs_entries); 2944 nfs_dir->nfs_entries = NULL; 2945 nfs_mux_release(nmp); 2946 return OK; 2947} 2948 2949int vfs_nfs_truncate(struct Vnode *node, off_t length) 2950{ 2951 uint32_t *ptr; 2952 int reqlen; 2953 int error; 2954 2955 struct nfsmount *nmp = NULL; 2956 struct nfsnode *np = NULL; 2957 2958 nmp = (struct nfsmount *)(node->originMount->data); 2959 nfs_mux_take(nmp); 2960 np = (struct nfsnode*)(node->data); 2961 2962 /* Create the SETATTR RPC call arguments */ 2963 2964 ptr = (uint32_t *)&nmp->nm_msgbuffer.setattr.setattr; 2965 reqlen = 0; 2966 2967 /* Copy the variable length, directory file handle */ 2968 2969 *ptr++ = txdr_unsigned(np->n_fhsize); 2970 reqlen += sizeof(uint32_t); 2971 2972 (void)memcpy_s(ptr, np->n_fhsize, &np->n_fhandle, np->n_fhsize); 2973 reqlen += (int)np->n_fhsize; 2974 ptr += uint32_increment(np->n_fhsize); 2975 2976 /* Copy the variable-length attributes */ 2977 2978 *ptr++ = nfs_false; /* Don't change mode */ 2979 *ptr++ = nfs_false; /* Don't change uid */ 2980 *ptr++ = nfs_false; /* Don't change gid */ 2981 *ptr++ = nfs_true; /* Use the following size */ 2982 *ptr++ = length; /* Truncate to the specified length */ 2983 *ptr++ = 0; 2984 *ptr++ = htonl(NFSV3SATTRTIME_TOSERVER); /* Use the server's time */ 2985 *ptr++ = htonl(NFSV3SATTRTIME_TOSERVER); /* Use the server's time */ 2986 *ptr++ = nfs_false; /* No guard value */ 2987 reqlen += 9 * sizeof(uint32_t); 2988 2989 /* Perform the SETATTR RPC */ 2990 2991 nfs_statistics(NFSPROC_SETATTR); 2992 error = nfs_request(nmp, NFSPROC_SETATTR, 2993 (void *)&nmp->nm_msgbuffer.setattr, reqlen, 2994 (void *)nmp->nm_iobuffer, nmp->nm_buflen); 2995 if (error != OK) 2996 { 2997 nfs_mux_release(nmp); 2998 nfs_debug_error("nfs_request failed: %d\n", error); 2999 return -error; 3000 } 3001 3002 /* Indicate that the file now has zero length */ 3003 3004 np->n_size = length; 3005 nfs_mux_release(nmp); 3006 return OK; 3007} 3008 3009static int vfs_nfs_unmount(struct Mount *mnt, struct Vnode **blkDriver) 3010{ 3011 (void)blkDriver; 3012 struct nfsmount *nmp = (struct nfsmount *)mnt->data; 3013 int error; 3014 3015 DEBUGASSERT(nmp); 3016 3017 /* Get exclusive access to the mount structure */ 3018 3019 nfs_mux_take(nmp); 3020 3021 /* Are there any open files? We can tell if there are open files by looking 3022 * at the list of file structures in the mount structure. If this list 3023 * not empty, then there are open files and we cannot unmount now (or a 3024 * crash is sure to follow). 3025 * The root of nfs is the head of the nfsnode list, it will be released later, 3026 * so now skip checking it. 3027 */ 3028 if (nmp->nm_head == NULL) 3029 { 3030 error = ENODEV; 3031 goto errout_with_mutex; 3032 } 3033 3034 if (nmp->nm_head->n_next != NULL || nmp->nm_dir != NULL) 3035 { 3036 nfs_debug_error("There are open files: %p or directories: %p\n", nmp->nm_head, nmp->nm_dir); 3037 3038 /* This implementation currently only supports unmounting if there are 3039 * no open file references. 3040 */ 3041 3042 error = EBUSY; 3043 goto errout_with_mutex; 3044 } 3045 3046 /* No open file... Umount the file system. */ 3047 3048 error = rpcclnt_umount(nmp->nm_rpcclnt); 3049 if (error) 3050 { 3051 nfs_debug_error("rpcclnt_umount failed: %d\n", error); 3052 goto errout_with_mutex; 3053 } 3054 3055 /* Disconnect from the server */ 3056 3057 rpcclnt_disconnect(nmp->nm_rpcclnt); 3058 3059 /* And free any allocated resources */ 3060 3061 nfs_mux_release(nmp); 3062 (void)pthread_mutex_destroy(&nmp->nm_mux); 3063 free(nmp->nm_rpcclnt); 3064 nmp->nm_rpcclnt = NULL; 3065 free(nmp); 3066 nmp = NULL; 3067 3068 return -error; 3069 3070errout_with_mutex: 3071 nfs_mux_release(nmp); 3072 return -error; 3073} 3074 3075static int nfs_check_timestamp(struct timespec *origin, struct timespec *new) 3076{ 3077 return (origin->tv_sec == new->tv_sec) && (origin->tv_nsec == new->tv_nsec); 3078} 3079 3080static int vfs_nfs_open(struct file *filep) 3081{ 3082 int ret; 3083 struct timespec ts; 3084 struct rpc_call_fs attr_call; 3085 struct rpc_reply_getattr attr_reply; 3086 struct Vnode *node = filep->f_vnode; 3087 struct nfsnode *nfs_node = NULL; 3088 struct nfsmount *nmp = (struct nfsmount *)(node->originMount->data); 3089 struct file_handle parent_fhandle = {0}; 3090 3091 nfs_mux_take(nmp); 3092 nfs_node = (struct nfsnode *)node->data; 3093 attr_call.fs.fsroot.length = txdr_unsigned(nfs_node->n_fhsize); 3094 memcpy_s(&(attr_call.fs.fsroot.handle), sizeof(nfsfh_t), &(nfs_node->n_fhandle), sizeof(nfsfh_t)); 3095 3096 ret = nfs_request(nmp, NFSPROC_GETATTR, &attr_call, 3097 sizeof(struct file_handle), &attr_reply, 3098 sizeof(struct rpc_reply_getattr)); 3099 if (ret != OK) 3100 { 3101 if (ret == NFSERR_STALE) 3102 { 3103 /* If the file handle is stale, update it */ 3104 OsFileCacheRemove(&(node->mapping)); 3105 parent_fhandle.length = ((struct nfsnode *)node->parent->data)->n_fhsize; 3106 memcpy_s(&(parent_fhandle.handle), parent_fhandle.length, 3107 &(((struct nfsnode *)node->parent->data)->n_fhandle), 3108 ((struct nfsnode *)node->parent->data)->n_fhsize); 3109 ret = nfs_fileupdate(nmp, nfs_node->n_name, &parent_fhandle, nfs_node); 3110 } 3111 nfs_mux_release(nmp); 3112 return ret; 3113 } 3114 3115 /* Extract time values as timestamp */ 3116 3117 fxdr_nfsv3time(&attr_reply.attr.fa_mtime, &ts); 3118 if (!nfs_check_timestamp(&(nfs_node->n_timestamp), &ts)) 3119 { 3120 OsFileCacheRemove(&(node->mapping)); 3121 nfs_node->n_timestamp.tv_sec = ts.tv_sec; 3122 nfs_node->n_timestamp.tv_nsec = ts.tv_nsec; 3123 } 3124 3125 nfs_mux_release(nmp); 3126 3127 return OK; 3128} 3129 3130struct MountOps nfs_mount_operations = 3131{ 3132 .Mount = vfs_nfs_mount, 3133 .Unmount = vfs_nfs_unmount, 3134 .Statfs= vfs_nfs_statfs, 3135}; 3136 3137struct VnodeOps nfs_vops = 3138{ 3139 .Lookup = vfs_nfs_lookup, 3140 .Getattr = vfs_nfs_stat, 3141 .Opendir = vfs_nfs_opendir, 3142 .Readdir = vfs_nfs_readdir, 3143 .Rename = vfs_nfs_rename, 3144 .Mkdir = vfs_nfs_mkdir, 3145 .Create = vfs_nfs_create, 3146 .ReadPage = vfs_nfs_readpage, 3147 .WritePage = vfs_nfs_writepage, 3148 .Unlink = vfs_nfs_unlink, 3149 .Rmdir = vfs_nfs_rmdir, 3150 .Reclaim = vfs_nfs_reclaim, 3151 .Closedir = vfs_nfs_closedir, 3152 .Close = vfs_nfs_close, 3153 .Rewinddir = vfs_nfs_rewinddir, 3154 .Truncate = vfs_nfs_truncate, 3155}; 3156 3157struct file_operations_vfs nfs_fops = 3158{ 3159 .open = vfs_nfs_open, 3160 .seek = vfs_nfs_seek, 3161 .write = vfs_nfs_write, 3162 .read = vfs_nfs_read, 3163 .mmap = OsVfsFileMmap, 3164 .close = vfs_nfs_close_file, 3165}; 3166FSMAP_ENTRY(nfs_fsmap, "nfs", nfs_mount_operations, FALSE, FALSE); 3167#endif 3168