xref: /third_party/NuttX/fs/nfs/nfs_adapter.c (revision beacf11b)
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