• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
81 uint32_t nfs_true;
82 uint32_t nfs_false;
83 uint32_t nfs_xdrneg1;
84 NFSMOUNT_HOOK g_NFSMOUNT_HOOK = (NFSMOUNT_HOOK)(UINTPTR)NULL;
85 
86 #ifdef CONFIG_NFS_STATISTICS
87 struct 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
122 struct MountOps nfs_mount_operations;
123 struct VnodeOps nfs_vops;
124 struct file_operations_vfs nfs_fops;
125 struct 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 };
134 extern void nfs_stat_common(struct nfs_statinfo_s *info, struct stat *buf);
135 
type_to_mode(int type,mode_t permission)136 static 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 
nfs_2_vfs(int result)156 static 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  ****************************************************************************/
nfs_fileupdate(struct nfsmount * nmp,char * filename,struct file_handle * parent_fhandle,struct nfsnode * np)193 static 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 
vfs_nfs_reclaim(struct Vnode * node)229 int 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 
vfs_nfs_stat_internal(struct nfsmount * nmp,struct nfsnode * nfs_node)300 static 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 
nfs_decode_args(struct nfs_mount_parameters * nprmt,struct nfs_args * argp)344 static 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 
nfs_bind(struct Vnode * blkdriver,const void * data,void ** handle,const char * relpath)486 int 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 
662 bad:
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 
filetype_to_vnodetype(uint32_t filetype)686 static 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 
nfs_mount(const char * server_ip_and_path,const char * mount_path,unsigned int uid,unsigned int gid)708 int 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 
785 nfs_free_node_out:
786   free(server_ip_addr);
787 
788 nfs_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 
vfs_nfs_mount(struct Mount * mnt,struct Vnode * device,const void * data)798 int 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 
vfs_nfs_lookup(struct Vnode * parent,const char * path,int len,struct Vnode ** vpp)848 int 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 
vfs_nfs_stat(struct Vnode * node,struct stat * buf)902 int 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 
vfs_nfs_opendir(struct Vnode * node,struct fs_dirent_s * dir)927 int 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 
961 errout_with_mutex:
962   nfs_mux_release(nmp);
963   return ret;
964 }
965 
vfs_nfs_readdir(struct Vnode * node,struct fs_dirent_s * dir)966 int 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 
1294 errout_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     }
1300 errout_with_mutex:
1301   nfs_mux_release(nmp);
1302   if (error == ENOENT && i > 0)
1303     {
1304       return i;
1305     }
1306   return -error;
1307 }
1308 extern int nfs_getfilename(char *dstpath, unsigned int dstpathLen, const char *srcpath, unsigned int maxlen);
1309 extern int nfs_rename(struct Vnode *mountpt, const char *oldrelpath, const char *newrelpath);
vfs_nfs_rename(struct Vnode * from_vnode,struct Vnode * to_parent,const char * from_name,const char * to_name)1310 int 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 
1401 errout_with_mutex:
1402   nfs_mux_release(nmp);
1403   return -error;
1404 }
1405 
vfs_nfs_mkdir(struct Vnode * parent,const char * dirname,mode_t mode,struct Vnode ** vpp)1406 int 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 
1549 errout_with_mutex:
1550   nfs_mux_release(nmp);
1551   return -error;
1552 }
1553 
vfs_nfs_write(struct file * filep,const char * buffer,size_t buflen)1554 int 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;
1766 errout_with_memfree:
1767   free(temp_buffer);
1768 errout_with_mutex:
1769   nfs_mux_release(nmp);
1770   return -error;
1771 }
1772 
vfs_nfs_writepage(struct Vnode * node,char * buffer,off_t pos,size_t buflen)1773 ssize_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;
1970 errout_with_memfree:
1971   free(temp_buffer);
1972 errout_with_mutex:
1973   nfs_mux_release(nmp);
1974   return -error;
1975 }
1976 
vfs_nfs_seek(struct file * filep,off_t offset,int whence)1977 off_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 
2042 errout_with_mutex:
2043   nfs_mux_release(nmp);
2044   return -error;
2045 }
2046 
vfs_nfs_readpage(struct Vnode * node,char * buffer,off_t pos)2047 ssize_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 
2192 errout_with_mutex:
2193   nfs_mux_release(nmp);
2194   return -error;
2195 }
2196 
vfs_nfs_read(struct file * filep,char * buffer,size_t buflen)2197 ssize_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 
2337 errout_with_mutex:
2338   nfs_mux_release(nmp);
2339   return -error;
2340 }
2341 
vfs_nfs_create(struct Vnode * parent,const char * filename,int mode,struct Vnode ** vpp)2342 int 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 
2526 errout_with_mutex:
2527   if (np)
2528     {
2529       free(np);
2530     }
2531   nfs_mux_release(nmp);
2532   return -error;
2533 }
2534 
vfs_nfs_unlink(struct Vnode * parent,struct Vnode * target,const char * filename)2535 int 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 
2594 errout_with_mutex:
2595   nfs_mux_release(nmp);
2596   return -error;
2597 }
2598 
vfs_nfs_rmdir(struct Vnode * parent,struct Vnode * target,const char * dirname)2599 int 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 
2656 errout_with_mutex:
2657   nfs_mux_release(nmp);
2658   return -nfs_2_vfs(error);
2659 }
2660 
2661 
vfs_nfs_close(struct Vnode * node)2662 int 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 
vfs_nfs_close_file(struct file * filep)2680 int 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 
vfs_nfs_closedir(struct Vnode * node,struct fs_dirent_s * dir)2686 int 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 
nfs_fsinfo(struct nfsmount * nmp)2764 int 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 
vfs_nfs_statfs(struct Mount * mountpt,struct statfs * sbp)2847 int 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 
2918 errout_with_mutex:
2919   nfs_mux_release(nmp);
2920   return -error;
2921 }
2922 
vfs_nfs_rewinddir(struct Vnode * node,struct fs_dirent_s * dir)2923 static 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 
vfs_nfs_truncate(struct Vnode * node,off_t length)2949 int 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 
vfs_nfs_unmount(struct Mount * mnt,struct Vnode ** blkDriver)3009 static 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 
3070 errout_with_mutex:
3071   nfs_mux_release(nmp);
3072   return -error;
3073 }
3074 
nfs_check_timestamp(struct timespec * origin,struct timespec * new)3075 static 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 
vfs_nfs_open(struct file * filep)3080 static 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 
3130 struct MountOps nfs_mount_operations =
3131 {
3132   .Mount = vfs_nfs_mount,
3133   .Unmount = vfs_nfs_unmount,
3134   .Statfs= vfs_nfs_statfs,
3135 };
3136 
3137 struct 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 
3157 struct 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 };
3166 FSMAP_ENTRY(nfs_fsmap, "nfs", nfs_mount_operations, FALSE, FALSE);
3167 #endif
3168